From 20ad9e9d93bee359489afd2d4dc3c8587dd0cf92 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Mon, 23 Nov 1998 14:28:09 +0000 Subject: New network driver from Erik Ivanenko . --- c/src/lib/libbsp/i386/i386ex/network/dma.h | 268 +++ c/src/lib/libbsp/i386/i386ex/network/netexterns.h | 13 + c/src/lib/libbsp/i386/i386ex/network/network.c | 2556 +++++++++++++++++++++ c/src/lib/libbsp/i386/i386ex/network/uti596.h | 276 +++ 4 files changed, 3113 insertions(+) create mode 100644 c/src/lib/libbsp/i386/i386ex/network/dma.h create mode 100644 c/src/lib/libbsp/i386/i386ex/network/netexterns.h create mode 100644 c/src/lib/libbsp/i386/i386ex/network/network.c create mode 100644 c/src/lib/libbsp/i386/i386ex/network/uti596.h (limited to 'c/src/lib/libbsp/i386/i386ex/network') diff --git a/c/src/lib/libbsp/i386/i386ex/network/dma.h b/c/src/lib/libbsp/i386/i386ex/network/dma.h new file mode 100644 index 0000000000..51c0d0c98a --- /dev/null +++ b/c/src/lib/libbsp/i386/i386ex/network/dma.h @@ -0,0 +1,268 @@ +/* $Id$ + * linux/include/asm/dma.h: Defines for using and allocating dma channels. + * Written by Hennus Bergman, 1992. + * High DMA channel support & info by Hannu Savolainen + * and John Boyd, Nov. 1992. + */ + +#ifndef _ASM_DMA_H +#define _ASM_DMA_H + + + +#define dma_outb(x,y) outport_byte(y,x) + +#define dma_inb inport_byte + +/* + * NOTES about DMA transfers: + * + * controller 1: channels 0-3, byte operations, ports 00-1F + * controller 2: channels 4-7, word operations, ports C0-DF + * + * - ALL registers are 8 bits only, regardless of transfer size + * - channel 4 is not used - cascades 1 into 2. + * - channels 0-3 are byte - addresses/counts are for physical bytes + * - channels 5-7 are word - addresses/counts are for physical words + * - transfers must not cross physical 64K (0-3) or 128K (5-7) boundaries + * - transfer count loaded to registers is 1 less than actual count + * - controller 2 offsets are all even (2x offsets for controller 1) + * - page registers for 5-7 don't use data bit 0, represent 128K pages + * - page registers for 0-3 use bit 0, represent 64K pages + * + * DMA transfers are limited to the lower 16MB of _physical_ memory. + * Note that addresses loaded into registers must be _physical_ addresses, + * not logical addresses (which may differ if paging is active). + * + * Address mapping for channels 0-3: + * + * A23 ... A16 A15 ... A8 A7 ... A0 (Physical addresses) + * | ... | | ... | | ... | + * | ... | | ... | | ... | + * | ... | | ... | | ... | + * P7 ... P0 A7 ... A0 A7 ... A0 + * | Page | Addr MSB | Addr LSB | (DMA registers) + * + * Address mapping for channels 5-7: + * + * A23 ... A17 A16 A15 ... A9 A8 A7 ... A1 A0 (Physical addresses) + * | ... | \ \ ... \ \ \ ... \ \ + * | ... | \ \ ... \ \ \ ... \ (not used) + * | ... | \ \ ... \ \ \ ... \ + * P7 ... P1 (0) A7 A6 ... A0 A7 A6 ... A0 + * | Page | Addr MSB | Addr LSB | (DMA registers) + * + * Again, channels 5-7 transfer _physical_ words (16 bits), so addresses + * and counts _must_ be word-aligned (the lowest address bit is _ignored_ at + * the hardware level, so odd-byte transfers aren't possible). + * + * Transfer count (_not # bytes_) is limited to 64K, represented as actual + * count - 1 : 64K => 0xFFFF, 1 => 0x0000. Thus, count is always 1 or more, + * and up to 128K bytes may be transferred on channels 5-7 in one operation. + * + */ + +#define MAX_DMA_CHANNELS 8 + +/* The maximum address that we can perform a DMA transfer to on this platform */ +#define MAX_DMA_ADDRESS 0x1000000 + +/* 8237 DMA controllers */ +#define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */ +#define IO_DMA2_BASE 0xC0 /* 16 bit master DMA, ch 4(=slave input)..7 */ + +/* DMA controller registers */ +#define DMA1_CMD_REG 0x08 /* command register (w) */ +#define DMA1_STAT_REG 0x08 /* status register (r) */ +#define DMA1_REQ_REG 0x09 /* request register (w) */ +#define DMA1_MASK_REG 0x0A /* single-channel mask (w) */ +#define DMA1_MODE_REG 0x0B /* mode register (w) */ +#define DMA1_CLEAR_FF_REG 0x0C /* clear pointer flip-flop (w) */ +#define DMA1_TEMP_REG 0x0D /* Temporary Register (r) */ +#define DMA1_RESET_REG 0x0D /* Master Clear (w) */ +#define DMA1_CLR_MASK_REG 0x0E /* Clear Mask */ +#define DMA1_MASK_ALL_REG 0x0F /* all-channels mask (w) */ + +#define DMA2_CMD_REG 0xD0 /* command register (w) */ +#define DMA2_STAT_REG 0xD0 /* status register (r) */ +#define DMA2_REQ_REG 0xD2 /* request register (w) */ +#define DMA2_MASK_REG 0xD4 /* single-channel mask (w) */ +#define DMA2_MODE_REG 0xD6 /* mode register (w) */ +#define DMA2_CLEAR_FF_REG 0xD8 /* clear pointer flip-flop (w) */ +#define DMA2_TEMP_REG 0xDA /* Temporary Register (r) */ +#define DMA2_RESET_REG 0xDA /* Master Clear (w) */ +#define DMA2_CLR_MASK_REG 0xDC /* Clear Mask */ +#define DMA2_MASK_ALL_REG 0xDE /* all-channels mask (w) */ + +#define DMA_ADDR_0 0x00 /* DMA address registers */ +#define DMA_ADDR_1 0x02 +#define DMA_ADDR_2 0x04 +#define DMA_ADDR_3 0x06 +#define DMA_ADDR_4 0xC0 +#define DMA_ADDR_5 0xC4 +#define DMA_ADDR_6 0xC8 +#define DMA_ADDR_7 0xCC + +#define DMA_CNT_0 0x01 /* DMA count registers */ +#define DMA_CNT_1 0x03 +#define DMA_CNT_2 0x05 +#define DMA_CNT_3 0x07 +#define DMA_CNT_4 0xC2 +#define DMA_CNT_5 0xC6 +#define DMA_CNT_6 0xCA +#define DMA_CNT_7 0xCE + +#define DMA_PAGE_0 0x87 /* DMA page registers */ +#define DMA_PAGE_1 0x83 +#define DMA_PAGE_2 0x81 +#define DMA_PAGE_3 0x82 +#define DMA_PAGE_5 0x8B +#define DMA_PAGE_6 0x89 +#define DMA_PAGE_7 0x8A + +#define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */ +#define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */ +#define DMA_MODE_CASCADE 0xC0 /* pass thru DREQ->HRQ, DACK<-HLDA only */ + +/* enable/disable a specific DMA channel */ +static __inline__ void enable_dma(unsigned int dmanr) +{ + if (dmanr<=3) + {dma_outb(dmanr, DMA1_MASK_REG);} + else + {dma_outb(dmanr & 3, DMA2_MASK_REG);} +} + +static __inline__ void disable_dma(unsigned int dmanr) +{ + if (dmanr<=3) + { dma_outb(dmanr | 4, DMA1_MASK_REG); } + else + { dma_outb((dmanr & 3) | 4, DMA2_MASK_REG);} +} + +/* Clear the 'DMA Pointer Flip Flop'. + * Write 0 for LSB/MSB, 1 for MSB/LSB access. + * Use this once to initialize the FF to a known state. + * After that, keep track of it. :-) + * --- In order to do that, the DMA routines below should --- + * --- only be used while interrupts are disabled! --- + */ +static __inline__ void clear_dma_ff(unsigned int dmanr) +{ + if (dmanr<=3) + {dma_outb(0, DMA1_CLEAR_FF_REG);} + else + {dma_outb(0, DMA2_CLEAR_FF_REG);} +} + +/* set mode (above) for a specific DMA channel */ +static __inline__ void set_dma_mode(unsigned int dmanr, char mode) +{ + if (dmanr<=3) + { dma_outb(mode | dmanr, DMA1_MODE_REG);} + else + { dma_outb(mode | (dmanr&3), DMA2_MODE_REG);} +} + +/* Set only the page register bits of the transfer address. + * This is used for successive transfers when we know the contents of + * the lower 16 bits of the DMA current address register, but a 64k boundary + * may have been crossed. + */ +static __inline__ void set_dma_page(unsigned int dmanr, char pagenr) +{ + switch(dmanr) { + case 0: + {dma_outb(pagenr, DMA_PAGE_0);} + break; + case 1: + {dma_outb(pagenr, DMA_PAGE_1);} + break; + case 2: + {dma_outb(pagenr, DMA_PAGE_2);} + break; + case 3: + {dma_outb(pagenr, DMA_PAGE_3);} + break; + case 5: + {dma_outb(pagenr & 0xfe, DMA_PAGE_5);} + break; + case 6: + {dma_outb(pagenr & 0xfe, DMA_PAGE_6);} + break; + case 7: + {dma_outb(pagenr & 0xfe, DMA_PAGE_7);} + break; + } +} + + +/* Set transfer address & page bits for specific DMA channel. + * Assumes dma flipflop is clear. + */ +static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a) +{ + set_dma_page(dmanr, a>>16); + if (dmanr <= 3) { + dma_outb( a & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE ); + dma_outb( (a>>8) & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE ); + } else { + dma_outb( (a>>1) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE ); + dma_outb( (a>>9) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE ); + } +} + + +/* Set transfer size (max 64k for DMA1..3, 128k for DMA5..7) for + * a specific DMA channel. + * You must ensure the parameters are valid. + * NOTE: from a manual: "the number of transfers is one more + * than the initial word count"! This is taken into account. + * Assumes dma flip-flop is clear. + * NOTE 2: "count" represents _bytes_ and must be even for channels 5-7. + */ +static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count) +{ + count--; + if (dmanr <= 3) { + dma_outb( count & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE ); + dma_outb( (count>>8) & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE ); + } else { + dma_outb( (count>>1) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE ); + dma_outb( (count>>9) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE ); + } +} + + +/* Get DMA residue count. After a DMA transfer, this + * should return zero. Reading this while a DMA transfer is + * still in progress will return unpredictable results. + * If called before the channel has been used, it may return 1. + * Otherwise, it returns the number of _bytes_ left to transfer. + * + * Assumes DMA flip-flop is clear. + */ +static __inline__ int get_dma_residue(unsigned int dmanr) +{ + unsigned int io_port = (dmanr<=3)? ((dmanr&3)<<1) + 1 + IO_DMA1_BASE + : ((dmanr&3)<<2) + 2 + IO_DMA2_BASE; + + /* using short to get 16-bit wrap around */ + unsigned short count,temp; + + dma_inb(io_port,count); + count ++; + dma_inb(io_port,temp); + count += temp << 8; + + return (dmanr<=3)? count : (count<<1); +} + + + + +#endif /* _ASM_DMA_H */ + + + diff --git a/c/src/lib/libbsp/i386/i386ex/network/netexterns.h b/c/src/lib/libbsp/i386/i386ex/network/netexterns.h new file mode 100644 index 0000000000..26ddc806a9 --- /dev/null +++ b/c/src/lib/libbsp/i386/i386ex/network/netexterns.h @@ -0,0 +1,13 @@ +#ifndef NET_EXTERNS_H +#define NET_EXTERNS_H + +/* + * External entry points + */ + +extern int uti596_attach(struct rtems_bsdnet_ifconfig *); +extern int uti596dump(char * ); +extern void uti596reset(void); +extern void uti596Diagnose(int); + +#endif diff --git a/c/src/lib/libbsp/i386/i386ex/network/network.c b/c/src/lib/libbsp/i386/i386ex/network/network.c new file mode 100644 index 0000000000..b126e4e623 --- /dev/null +++ b/c/src/lib/libbsp/i386/i386ex/network/network.c @@ -0,0 +1,2556 @@ +/* uti596.c: An 82596 ethernet driver for rtems-bsd. */ +void dump_scb(void); + +#ifdef DBG_VERSION +#define BREAKPOINT() asm(" int $3"); +#else +#define BREAKPOINT() +#endif + +#define KERNEL + + +int forceResetRX = 0; +int forceResetTX = 0; + + +/* + + EII: Oct 16 : Version 0.0 + + +*/ + +#define DMA_MODE_CASCADE 0xC0 /* pass thru DREQ->HRQ, DACK<-HLDA only */ +#define DMA_MASK_REG 0x0A +#define DMA_MODE_REG 0x0B +#define DMA_ENABLE 0x0 +#define DMA_DISABLE 0x4 + +struct i596_rfd *pISR_Rfd; + + +#define MY_PRINT_1( msg, p1 ) { char buffer[80]; int i,j; sprintf(buffer, msg, p1 );j=strlen(buffer); for ( i=0;i +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include "uti596.h" +#include "netexterns.h" + +#include + +int reset_bit_test = 0; + +/* #include "../misc/utils.h" */ + +static struct uti596_softc uti596_softc; + +void uti596rxStart(int); +int uti596packetNumber = 0; + +static int scbStatus; +static rtems_status_code sc; +static struct i596_cmd *pIsrCmd; +static struct i596_rfd *pIsrRfd; + +/* + * Initial 596 configuration + */ +char uti596initSetup[] = { + 0x0E, /* length, prefetch off ( no RBD's ) */ + 0xC8, /* fifo to 8, monitor off */ + 0x40, /* don't save bad frames ( was save= 80, use intel's 40 )*/ + 0x2E, /* No source address insertion, 8 byte preamble */ + 0x00, /* priority and backoff defaults */ + 0x60, /* interframe spacing */ + 0x00, /* slot time LSB */ + 0xf2, /* slot time and retries */ + 0x0C, /* */ + 0x08, /* collision detect */ + 0x40, /* minimum frame length */ + 0xfb, /* tried C8 same as byte 1 in bits 6-7, else ignored*/ + 0x00, + 0x3f /* no multi IA */ }; +/* + * Externally defined symbols + */ +#define RX_BUF_COUNT 15 +#define TX_BUF_COUNT 4 +#define TX_BD_PER_BUF 4 + +#define INTERRUPT_EVENT RTEMS_EVENT_1 +#define START_TRANSMIT_EVENT RTEMS_EVENT_2 + +#define RBUF_SIZE 1520 + +#define UTI_596_RFD_NUMBER 4 + +/* + * Local Routines + */ + +/* These are extern, and non-inline for testing purposes */ + +void uti596addCmd (struct i596_cmd *pCmd); +void uti596_initMem (struct uti596_softc *); +void uti596_init (void * ); +int uti596initRxBufs (int num); +int uti596_initRFA (int num); +int uti596initRxBufs (int num); +static int uti596_ioctl (struct ifnet *, int, caddr_t); +rtems_isr uti596DynamicInterruptHandler (rtems_vector_number); + +void uti596_txDaemon (void *); +void uti596_rxDaemon (void *); + +void uti596_stop (struct uti596_softc *); +static void uti596_start (struct ifnet *); + +void uti596reset (void); + +void uti596_stats (struct uti596_softc *); + +void uti596_initialize_hardware(struct uti596_softc *); + +void uti596clearListStatus(struct i596_rfd *); +void uti596addPolledCmd(struct i596_cmd *); + +void uti596supplyFD(struct i596_rfd *); + +struct i596_rfd * uti596dequeue( struct i596_rfd ** ); +void uti596append( struct i596_rfd ** , struct i596_rfd * ); + +#ifdef DEBUG_INIT +static void print_eth (unsigned char *); +static void print_hdr (unsigned char *); +static void print_pkt (unsigned char *); +#endif + +void send_packet(struct ifnet *, struct mbuf *); + +#define UTI_596_IRQ 5 +#define UTI_596_ETH_MIN_SIZE 60 + +/* Waits for the command word to clear. The command word is cleared AFTER the interrupt is + * generated. This allows the CPU to issue the next command + */ +#define UTI_WAIT_COMMAND_ACCEPTED(duration,function)\ +{ int waitcount = duration; \ + while ( uti596_softc.scb.command ) \ + if (--waitcount == 0) \ + { \ + printk("%s: i82596 timed out with status %x, cmd %x.\n", function, \ + uti596_softc.scb.status, uti596_softc.scb.command); \ + break; \ + } \ +} + + + +static void nopOn(const rtems_irq_connect_data* notUsed) +{ + /* + * code should be moved from initialize_hardware + * to this location ? + */ +} + +static int uti596_isOn(const rtems_irq_connect_data* irq) +{ + return BSP_irq_enabled_at_i8259s (irq->name); +} + + +/*********************************************************************** + * Function: uti596initRFA(int num) ( New ) + * + * Description: + * attempts to allocate and initialize ( chain together ) + * the requested number of FD's + * + * Algorithm: + * + ***********************************************************************/ + + +int uti596_initRFA(int num) +{ + struct i596_rfd *pRfd; + int i = 0; + + +#ifdef DBG_596 + printf ("%s: uti596_initRFA %d.\n", num); +#endif + + /* + * Initialize the first rfd in the rfa + */ + pRfd = (struct i596_rfd *) calloc (1,sizeof (struct i596_rfd)); + if ( !pRfd ) { + printf("Can't allocate all buffers: only %d allocated\n", i); + return 0; + } + else { + uti596_softc.countRFD = 1; + uti596_softc.pBeginRFA = uti596_softc.pEndRFA = pRfd; + printf ( "First Rfd allocated is: %p\n", + uti596_softc.pBeginRFA); + } + + for (i = 1; i < num; i++) { + pRfd = (struct i596_rfd *) calloc (1,sizeof (struct i596_rfd) ); + if ( pRfd != NULL ) { + uti596_softc.countRFD++; + uti596_softc.pEndRFA -> next = pRfd; /* link it in */ + uti596_softc.pEndRFA = pRfd; /* move the end */ +#ifdef DBG_596_RFA + printf("Allocated RFD @ %p\n", pRfd); +#endif + } + else { + printf("Can't allocate all buffers: only %d allocated\n", i); + break; + } + } /* end for */ + + uti596_softc.pEndRFA -> next = I596_NULL; + UTI_596_ASSERT(uti596_softc.countRFD == UTI_596_RFD_NUMBER,"INIT:WRONG RFD COUNT\n" ); + +#ifdef DBG_596_RFA + printf ( "Head of RFA is buffer %p\nEnd of RFA is buffer %p \n", + uti596_softc.pBeginRFA, + uti596_softc.pEndRFA ); +#endif + /* initialize the Rfd's */ + for ( pRfd = uti596_softc.pBeginRFA; + pRfd != I596_NULL; + pRfd = pRfd -> next ) { + + pRfd->cmd = 0x0000; + pRfd->stat = 0x0000; + pRfd->pRbd = I596_NULL; + pRfd->count = 0; /* number of bytes in buffer: usually less than size */ + pRfd->size = 1532; /* was 1532; buffer size ( All RBD ) */ + if ( pRfd -> data == NULL ) + printf("Can't allocate the RFD data buffer\n"); + } + + /* mark the last FD */ + uti596_softc.pEndRFA -> cmd = CMD_EOL; /* moved jan 13 from before the init stuff */ + +#ifdef DBG_596_RFA + printf ( "Head of RFA is buffer @ %p \n", uti596_softc.pBeginRFA ); +#endif + + + uti596_softc.pSavedRfdQueue = + uti596_softc.pEndSavedQueue = I596_NULL; /* initially empty */ + + uti596_softc.savedCount = 0; + + return (i); /* the number of allocated buffers */ + +} +/*********************************************************************** + * Function: uti596supplyFD + * + * Description: returns a buffer to the receive frame pool. + * call this with Inetrrupts disabled! + * + * Algorithm: + * + ***********************************************************************/ +void uti596supplyFD(struct i596_rfd * pRfd ) +{ + struct i596_rfd *pLastRfd; + + + UTI_596_ASSERT(pRfd != I596_NULL, "Supplying NULL RFD!\n"); + pRfd -> cmd = CMD_EOL; + pRfd -> pRbd = I596_NULL; + pRfd -> next = I596_NULL; + pRfd -> stat = 0x0000; /* clear STAT_C and STAT_B bits */ + + /* + * Check if the list is empty: + */ + if ( uti596_softc.pBeginRFA == I596_NULL ) { + /* Init a list w/ one entry */ + uti596_softc.pBeginRFA = uti596_softc.pEndRFA = pRfd; + UTI_596_ASSERT(uti596_softc.countRFD == 0, "Null begin, but non-zero count\n"); + if ( uti596_softc.pLastUnkRFD != I596_NULL ) + printf("LastUnkRFD is NOT NULL!!\n"); + uti596_softc.countRFD = 1; + return; + } + /* + * Check if the last RFD is used/read by the 596. + */ + pLastRfd = uti596_softc.pEndRFA; + + if ( pLastRfd != I596_NULL && + ! (pLastRfd -> stat & ( STAT_C | STAT_B ) )) { /* C = complete, B = busy (prefetched) */ + + /* + * Not yet too late to add it + */ + pLastRfd -> next = pRfd; + pLastRfd -> cmd &= ~CMD_EOL; /* RESET_EL : reset EL bit to 0 */ + uti596_softc.countRFD++; /* Lets assume we add it successfully + If not, the RFD may be used, and may decrement countRFD < 0 !!*/ + /* if (uti596_softc.countRFD > UTI_596_RFD_NUMBER) { + printf( "Supply: Count too high, count == %d, when adding %p\n",uti596_softc.countRFD, pRfd); + dumpQ(); + } + */ + /* + * Check if the last RFD was used while appending. + */ + if ( pLastRfd -> stat & ( STAT_C | STAT_B ) ) { /* completed or was prefetched */ + /* + * Either the EL bit of the last rfd has been read by the 82596, + * and it will stop after reception,( true when RESET_EL not reached ) or + * the EL bit was NOT read by the 82596 and it will use the linked + * RFD for the next reception. ( true is RESET_EL was reached ) + * So, it is unknown whether or not the linked rfd will be used. + * Therefore, the end of list CANNOT be updated. + */ + UTI_596_ASSERT ( uti596_softc.pLastUnkRFD == I596_NULL, "Too many Unk RFD's\n" ); + uti596_softc.pLastUnkRFD = pRfd; + return; + } + else { + /* + * The RFD being added was not touched by the 82596 + */ + if (uti596_softc.pLastUnkRFD != I596_NULL ) { + /* printf("Before appending\n"); + dumpQ(); */ + uti596append(&uti596_softc.pSavedRfdQueue, pRfd); /* Only here! saved Q */ + uti596_softc.pEndSavedQueue = pRfd; + uti596_softc.savedCount++; + uti596_softc.countRFD--; + /* printf("Last UNK must be NULL: %p\n",uti596_softc.pLastUnkRFD); + dumpQ(); */ + } + else { + uti596_softc.pEndRFA = pRfd; /* the RFA has been extended */ + if ( ( uti596_softc.scb.status & SCB_STAT_RNR || + uti596_softc.scb.status & RU_NO_RESOURCES ) && + uti596_softc.countRFD > 1 ) { /* was == 2 */ + uti596_softc.pBeginRFA -> cmd &= ~CMD_EOL; /* Ensure that beginRFA is not EOL */ + + UTI_596_ASSERT(uti596_softc.pEndRFA -> next == I596_NULL, "supply: List is buggered\n"); + UTI_596_ASSERT(uti596_softc.pEndRFA -> cmd & CMD_EOL, "supply: No EOL at end.\n"); + UTI_596_ASSERT(uti596_softc.scb.command == 0, "Supply: scb command must be zero\n"); +#ifdef DBG_START + printf("B"); +#endif + uti596rxStart(SCB_STAT_RNR); /*Ack the RNR interrupt */ + + } + } + return; + + } + } + else { + /* + * too late , pLastRfd in use ( or NULL ), + * in either case, EL bit has been read, and RNR condition will occur + */ + uti596append( &uti596_softc.pSavedRfdQueue, pRfd); /* save it for RNR */ + + uti596_softc.pEndSavedQueue = pRfd; /* reset end of saved queue */ + uti596_softc.savedCount++; + + + return; + } +} + +void uti596rxStart(int cmd) +{ + UTI_596_ASSERT(uti596_softc.pBeginRFA != I596_NULL, "rx start w/ NULL begin! \n"); + uti596_softc.scb.pRfd = uti596_softc.pBeginRFA; + uti596_softc.scb.command = RX_START | cmd; /* Don't ack RNR! The receiver should be stopped in this case */ + UTI_596_ASSERT( !(uti596_softc.scb.status & SCB_STAT_FR),"FRAME RECEIVED INT COMING!\n"); + outport_byte(CHAN_ATTN, 0); +} + +static void +uti596_start (struct ifnet *ifp) +{ + struct uti596_softc *sc = ifp->if_softc; + + rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT); + ifp->if_flags |= IFF_OACTIVE; +} + +void +uti596_initialize_hardware(struct uti596_softc *sc) +{ + int boguscnt = 1000; + rtems_status_code status_code; + + /* reset the board */ + outport_word( PORT_ADDR, 0 ); + outport_word( PORT_ADDR, 0 ); + + sc->pScp = (struct i596_scp *) + calloc(1,sizeof(struct i596_scp) + 0xf); +#ifdef DBG_INIT + printf("initialize_hardware:Scp address initially %p\n", sc->pScp); +#endif + sc->pScp = (struct i596_scp *) + ((((int)uti596_softc.pScp) + 0xf) & 0xfffffff0); + + +#ifdef DBG_INIT + printf("initialize_hardware:change scp address to : %p\n",sc->pScp); +#endif + + + /* change the scp address */ + + printf("Change the SCP address\n"); + + /* + * Set the DMA mode to enable the 82596 to become a bus-master + */ + outport_byte(DMA_MASK_REG,DMA_DISABLE); /* disable_dma */ + outport_byte(DMA_MODE_REG,DMA_MODE_CASCADE); /* set dma mode */ + outport_byte(DMA_MASK_REG,DMA_ENABLE); /* enable dma */ + + /* reset the board */ + outport_word( PORT_ADDR, 0 ); + outport_word( PORT_ADDR, 0 ); + + outport_word(PORT_ADDR, ((((int)uti596_softc.pScp) & 0xffff) | 2 )); + outport_word(PORT_ADDR, (( (int)uti596_softc.pScp) >> 16 ) & 0xffff ); + + /* This is linear mode, LOCK function is disabled */ + + sc->pScp->sysbus = 0x00540000; + sc->pScp->iscp = &sc->iscp; + sc->iscp.scb = &sc->scb; + sc->iscp.stat = 0x0001; + + sc->pCmdHead = sc->scb.pCmd = I596_NULL; + +#ifdef DBG_596 + printf("Starting i82596.\n"); +#endif + + /* Pass the scb address to the 596 */ + outport_word(CHAN_ATTN,0); + + while (sc->iscp.stat) + if (--boguscnt == 0) + { + printf("initialize_hardware: timed out with status %4.4lx\n", + sc->iscp.stat ); + break; + } + + /* clear the command word */ + sc->scb.command = 0; + + /* + * Set up interrupts ( NEW irq style ) + */ + sc->irqInfo.name = UTI_596_IRQ; + sc->irqInfo.hdl = ( void * ) uti596DynamicInterruptHandler; + sc->irqInfo.on = nopOn; + sc->irqInfo.off = nopOn; + sc->irqInfo.isOn = uti596_isOn; + + status_code = BSP_install_rtems_irq_handler (&sc->irqInfo); + if (!status_code) + rtems_panic ("Can't attach uti596 interrupt handler for irq %d\n", + sc->irqInfo.name); + + /* Initialize the 82596 memory ( Transmit buffers ) */ + uti596_initMem(sc); + + /* + * Create a semaphore to guard the critical sections within 596raw + * IS THIS NEEDED W/ FreeBSD? + */ + /* sc->semaphore_name = rtems_build_name('I','5','9','6'); + status_code = rtems_semaphore_create(sc->semaphore_name, + UTI596_MUTEX, + RTEMS_DEFAULT_ATTRIBUTES, + RTEMS_NO_PRIORITY, + &sc->semaphore_id); + */ +#ifdef DBG_INIT + printf("After attach, status of board = 0x%x\n", sc->scb.status ); +#endif + outport_word(0x380, 0xf); /* reset the LED's */ +} + + +/*********************************************************************** + * Function: uti596_initMem + * + * Description: + * creates the necessary descriptors for the + * uti596 board, hooks the interrupt, and starts the board. + * Assumes that interrupts are hooked. + * + * Algorithm: + * + ***********************************************************************/ + + + void +uti596_initMem(struct uti596_softc * sc) +{ + int i,count; + struct i596_tbd *pTbd; + + sc->resetDone = 0; /* ??? */ + + /* + * Set up receive frame area (RFA) + */ + i = uti596_initRFA( sc->rxBdCount ); + if ( i < sc->rxBdCount ) + printf("init_rfd: only able to allocate %d receive frame descriptors\n", i); + + sc->scb.pRfd = sc->pBeginRFA; + +#ifdef DBG_INIT + printf(" IRQ %d.\n", sc->irqInfo.name); +#endif + + /* + * Diagnose the health of the board + */ + uti596Diagnose(1); + + /* + * set up the i596 config command + */ +#ifdef DBG_INIT + printf("Configuring\n"); +#endif + + sc->set_conf.cmd.command = CmdConfigure; + memcpy (sc->set_conf.data, uti596initSetup, 14); + uti596addPolledCmd( (struct i596_cmd *) &sc->set_conf); + + /**** + * POLL + ****/ + + count = 2000; + while( !( sc->set_conf.cmd.status & STAT_C ) && --count ) + printf("."); + + if ( count ) + printf("Configure OK, count = %d\n",count); + else + printf("***Configure failed\n"); + + /*******/ + + /* + * Create the IA setup command + */ + +#ifdef DBG_INIT + printf("Setting Address\n"); +#endif + sc->set_add.cmd.command = CmdSASetup; + for ( i=0; i<6; i++) + sc->set_add.data[i]=sc->arpcom.ac_enaddr[i]; + + sc->cmdOk = 0; + uti596addPolledCmd((struct i596_cmd *)&sc->set_add); + /*******/ + + count = 2000; + while( !(sc->set_add.cmd.status & STAT_C ) && --count) + printf("."); + + if ( count ) + printf ("Set Address OK, count= %d\n",count); + else + printf("Set Address Failed\n"); + /*******/ + +#ifdef DBG_INIT + printf( "After initialization, status and command: 0x%x, 0x%x\n", + sc->scb.status, sc->scb.status); + +#endif + + /* initialize transmit buffer descriptors*/ + sc->pLastUnkRFD = I596_NULL; + sc->pTxCmd = (struct tx_cmd *) calloc (1,sizeof (struct tx_cmd) ); + sc->pTbd = (struct i596_tbd *) calloc (1,sizeof (struct i596_tbd) ); + sc->pTxCmd -> pTbd = sc->pTbd; + sc->pTxCmd->cmd.command = CMD_FLEX|CmdTx; + sc->pTxCmd->pad = 0; + sc->pTxCmd->size = 0; /* all bytes are in list of TBD's */ + + pTbd = sc->pTbd; + + for ( i=0; itxBdCount; i++) + pTbd = pTbd -> next = (struct i596_tbd *) calloc (1,sizeof (struct i596_tbd) ); + + pTbd -> next = I596_NULL; + + memset ( &sc->zeroes, 0, 64); + +#ifdef DBG_596 + printf( "After receiver start, status and command: 0x%x, 0x%x\n", + sc->scb.status, sc->scb.status); +#endif + printf("uti596_initMem allows ISR's\n"); + sc->resetDone = 1; /* now need ISR */ + +} + + + +/*********************************************************************** + * Function: uti596dump + * + * Description: Dump 596 registers + * + * Algorithm: + ***********************************************************************/ +/* static */ int +uti596dump(char * pDumpArea) +{ + struct i596_dump dumpCmd; + int boguscnt = 25000000; /* over a second! */ + + +#ifdef DBG_596 +printf("uti596dump:\n"); +#endif + + dumpCmd.cmd.command = CmdDump; + dumpCmd.cmd.next = I596_NULL; + dumpCmd.pData = pDumpArea; + uti596_softc.cmdOk = 0; + uti596addCmd ( (struct i596_cmd *)&dumpCmd); + while (1) + if ( --boguscnt == 0){ + printf("Dump command was not processed within spin loop delay\n"); + return 0; + } + else { + if ( uti596_softc.cmdOk ) + return 1; /* successful completion */ + } + + +} + +/*********************************************************************** + * Function: uti596_rxDaemon + * + * Description: Receiver task + * + * Algorithm: Extract the packet from an RFD, and place into an + * mbuf chain. Place the mbuf chain in the network task + * queue. Assumes that the frame check sequence is removed + * by the 82596. + * + ***********************************************************************/ + +/* static */ void +uti596_rxDaemon(void *arg) +{ + struct uti596_softc *sc = (struct uti596_softc *)arg; + struct ifnet *ifp = &sc->arpcom.ac_if; + struct mbuf *m; + + struct i596_rfd *pRfd; + ISR_Level level; + int tid,i; + rtems_event_set events; + struct ether_header *eh; + + int frames = 0; + +#ifdef DBG_596 + printf ("uti596_rxDaemon\n"); + printf("&scb = %p, pRfd = %p\n", &sc->scb,sc->scb.pRfd); +#endif + + rtems_task_ident (0, 0, &tid); + +#ifdef DBG_596 + printf("RX tid = 0x%x\n", tid); +#endif + + for(;;) { + /* + * Wait for packet. + */ +#ifdef DBG_596 + printf("Receiver sleeps\n"); +#endif + + rtems_bsdnet_event_receive (INTERRUPT_EVENT, + RTEMS_WAIT|RTEMS_EVENT_ANY, + RTEMS_NO_TIMEOUT, + &events); + +#ifdef DBG_596 + printf("Receiver wakes\n"); +#endif + /* + * While received frames are available. Note that the frame may be + * a fragment, so it is NOT a complete packet. + */ + pRfd = uti596dequeue( &sc->pInboundFrameQueue); + while ( pRfd && + pRfd != I596_NULL && + pRfd -> stat & STAT_C ) + { + +#ifdef DEBUG_INIT + printf("\nReceived packet:\n"); + print_eth( pRfd->data); +#endif + if ( pRfd->stat & STAT_OK){ + /* a good frame. Allocate an mbuf to take it from the queue */ + + int pkt_len = pRfd->count & 0x3fff; /* the actual # of bytes received */ + +#ifdef DBG_596 + printf("Good frame, @%p, data @%p length %d\n", pRfd, pRfd -> data , pkt_len); +#endif + frames++; + + + /* + * Allocate an mbuf to give to the stack + * The format of the data portion of the RFD is: + * . + * The FRAME CHECK SEQUENCE / CRC is stripped by the uti596. + * This is to be optimized later.... should not have to memcopy! + */ + MGETHDR(m, M_WAIT, MT_DATA); + MCLGET(m, M_WAIT); + + m->m_pkthdr.rcvif = ifp; + /* move everything into an mbuf */ + memcpy(m->m_data, + pRfd->data, + pkt_len); + + m->m_len = m->m_pkthdr.len = pkt_len - sizeof(struct ether_header) - 4; + + /* move the header to an mbuf */ + eh = mtod (m, struct ether_header *); + m->m_data += sizeof(struct ether_header); + +#ifdef DBG_596 + printf("m->m_ext: %p pRfd -> data: %p\n", + m->m_ext, pRfd -> data); +#endif +#ifdef DEBUG_INIT_2 + printf("mbuf contains:\n"); + print_eth( (char *) (((int)m->m_data)-sizeof(struct ether_header))); + for ( i = 0; i<20; i++) + printf("."); + +#endif +#ifdef DBG_VERSION + BREAKPOINT(); +#endif + ether_input (ifp, eh, m); + + } /* end if STAT_OK */ + + else { + /* + * A bad frame is present: Note that this could be the last RFD! + */ +#ifdef DBG_596 + printf("Bad frame\n"); +#endif + /* + * FIX ME: use the statistics from the SCB + */ + sc->stats.rx_errors++; + if ((sc->scb.pRfd->stat) & 0x0001) + sc->stats.collisions++; + if ((sc->scb.pRfd->stat) & 0x0080) + sc->stats.rx_length_errors++; + if ((sc->scb.pRfd->stat) & 0x0100) + sc->stats.rx_over_errors++; + if ((sc->scb.pRfd->stat) & 0x0200) + sc->stats.rx_fifo_errors++; + if ((sc->scb.pRfd->stat) & 0x0400) + sc->stats.rx_frame_errors++; + if ((sc->scb.pRfd->stat) & 0x0800) + sc->stats.rx_crc_errors++; + if ((sc->scb.pRfd->stat) & 0x1000) + sc->stats.rx_length_errors++; + } + + UTI_596_ASSERT(pRfd != I596_NULL, "Supplying NULL RFD\n"); + +#ifdef DBG_SUPPLY_FD + printf("Supply FD Starting\n"); +#endif + _ISR_Disable(level); + uti596supplyFD ( pRfd ); /* Return RFD to RFA. CAN WE REALLY?*/ + _ISR_Enable(level); +#ifdef DBG_SUPPLY_FD + printf("Supply FD Complete\n"); +#endif +#ifdef DBG_VERSION + BREAKPOINT(); +#endif + + pRfd = uti596dequeue( &sc->pInboundFrameQueue); /* grab next frame */ + + } /* end while */ + } /* end for(;;)*/ + +#ifdef DBG_596 + printf ("frames %d\n", frames); +#endif + +} + + /*********************************************************************** + * Function: uti596clearListStatus + * + * Description: + * Clear the stat fields for all rfd's + * Algorithm: + * + ***********************************************************************/ + +void +uti596clearListStatus(struct i596_rfd *pRfd) +{ + + while ( pRfd != I596_NULL ) { + pRfd -> stat = 0; /* clear the status field */ + pRfd = pRfd-> next; + } +} + + + /* static inline */ void uti596reset_bit_test() + { + reset_bit_test = 1; + } + +void uti596reset(void) + { + int i; + +#ifdef DBG_596_RESET + printf ("i596reset\n"); +#endif + + uti596_initialize_hardware(&uti596_softc); /* resets the ethernet hardware, now must re-config */ + uti596Diagnose(1); /* verbose diagnosis */ + + uti596_softc.set_conf.cmd.command = CmdConfigure; + memcpy (uti596_softc.set_conf.data, uti596initSetup, 14); + uti596addPolledCmd( (struct i596_cmd *) &uti596_softc.set_conf); + + while( !uti596_softc.set_conf.cmd.status & STAT_C ) + printf("."); + + printf("Configure completed\n"); +#ifdef DBG_596 + printf("Setting Address\n"); +#endif + uti596_softc.set_add.cmd.command = CmdSASetup; + for ( i=0; i<6; i++) + uti596_softc.set_add.data[i]= uti596_softc.arpcom.ac_enaddr[i]; + + uti596_softc.cmdOk = 0; + uti596addCmd((struct i596_cmd *)&uti596_softc.set_add); + /*******/ + while( !uti596_softc.set_add.cmd.status & STAT_C ) + printf("."); + /*******/ + +#ifdef DBG_596 + printf( "After initialization, status and command: 0x%x, 0x%x\n", + uti596_softc.scb.status, uti596_softc.scb.status); + +#endif + if ( uti596_softc.pLastUnkRFD != I596_NULL ) { + uti596_softc. pEndRFA = uti596_softc. pLastUnkRFD; /* The end position can be updated */ + uti596_softc. pLastUnkRFD = I596_NULL; + } + + /* clear status in RFA */ + uti596clearListStatus(uti596_softc.pBeginRFA ); + uti596clearListStatus(uti596_softc.pSavedRfdQueue ); + uti596_softc.scb.pRfd = uti596_softc.pBeginRFA; + + uti596_softc.scb.command = RX_START; + outport_word(CHAN_ATTN,0 ); + UTI_WAIT_COMMAND_ACCEPTED(4000, "init"); + + uti596_softc.started = 1; + } + + /*********************************************************************** + * Function: uti596addCmd + * + * Description: + * This routine adds a command onto the end of the + * command chain + * + * Algorithm: + * Add the command to the end of and existing chain, + * or start the chain and issue a CUC_START + * + * + ***********************************************************************/ + + /* static */ void uti596addCmd(struct i596_cmd *pCmd) + { + ISR_Level level; + + #ifdef DBG_596 + printf("Adding command 0x%x\n", pCmd -> command ); + #endif + +#ifdef DEBUG_ADD + + switch ( pCmd -> command & 0x7 ){ /* check bottom 7 bits */ + case CmdConfigure: + printf("ADD: Configure Command 0x%x\n", pCmd->command); + break; + case CmdSASetup: + printf("ADD: Set Address Command 0x%x\n", pCmd->command); + break; + case CmdMulticastList: + printf("ADD: Multi-cast list 0x%x\n", pCmd->command); + break; + case CmdNOp: + printf("ADD: NO op 0x%x\n", pCmd->command); + break; + case CmdTDR: + printf("ADD: TDR 0x%x\n", pCmd->command); + break; + case CmdDump: + printf("ADD: Dump 0x%x\n", pCmd->command); + break; + case CmdDiagnose: + printf("ADD: Diagnose 0x%x\n", pCmd->command); + break; + case CmdTx: + break; + default: + printf("****Unknown Command encountered 0x%x\n", pCmd->command); + break; + } /* end switch */ + +#endif + + + + pCmd->status = 0; + pCmd->command |= (CMD_EOL | CMD_INTR ); /* all commands last in list & return an interrupt */ + if ( reset_bit_test ){ + pCmd->command |= 0x0080; + printf("Issuing cmd: %#x\n", pCmd->command); + reset_bit_test = 0; + } + + pCmd->next = I596_NULL; + + _ISR_Disable(level); + if (uti596_softc.pCmdHead == I596_NULL) + { + uti596_softc.pCmdHead = + uti596_softc.pCmdTail = + uti596_softc.scb.pCmd = pCmd; +#ifdef DBG_596 + printf("First Cmd\n"); +#endif + UTI_WAIT_COMMAND_ACCEPTED(10000,"add command"); /* wait for acceptance of previous command */ + /* CHANGED TO |= Mar. 27 4:20 pm, was just =. changed back jun 18 1998. The wait assures command = 0 */ + uti596_softc.scb.command = CUC_START; + outport_word (CHAN_ATTN,0); + _ISR_Enable(level); + } + else + { +#ifdef DBG_596 + printf("Chained Cmd\n"); +#endif + uti596_softc.pCmdTail->next = pCmd; + uti596_softc.pCmdTail = pCmd; /* added Jan 30 */ + _ISR_Enable(level); + } + + +#ifdef DBG_596 + printf("Scb status & command 0x%x 0x%x\n", + uti596_softc.scb.status, + uti596_softc.scb.command ); +#endif + + } + + /*********************************************************************** + * Function: uti596addPolledCmd + * + * Description: + * This routine issues a single command then polls for it's + * completion. TO BE CALLED FROM ISR ONLY + * + * Algorithm: + * Give the command to the driver. ( CUC_START is ALWAYS required ) + * Poll for completion. + * + ***********************************************************************/ + +void uti596addPolledCmd(struct i596_cmd *pCmd) + { + + #ifdef DBG_596 + printf("Adding command 0x%x\n", pCmd -> command ); + #endif + +#ifdef DEBUG_POLLED_CMD + + switch ( pCmd -> command & 0x7 ){ /* check bottom 7 bits */ + case CmdConfigure: + printf("PolledCMD: Configure Command 0x%x\n", pCmd->command); + break; + case CmdSASetup: + printf("PolledCMD: Set CMDress Command 0x%x\n", pCmd->command); + break; + case CmdMulticastList: + printf("PolledCMD: Multi-cast list 0x%x\n", pCmd->command); + break; + case CmdNOp: + printf("PolledCMD: NO op 0x%x\n", pCmd->command); + break; + case CmdTDR: + printf("PolledCMD: TDR 0x%x\n", pCmd->command); + break; + case CmdDump: + printf("PolledCMD: Dump 0x%x\n", pCmd->command); + break; + case CmdDiagnose: + printf("PolledCMD: Diagnose 0x%x\n", pCmd->command); + break; + case CmdTx: + break; + default: + printf("PolledCMD: ****Unknown Command encountered 0x%x\n", pCmd->command); + break; + } /* end switch */ + +#endif + + pCmd->status = 0; + pCmd->command |= CMD_EOL ; /* only command in list*/ + + pCmd->next = I596_NULL; + + uti596_softc.pCmdHead = uti596_softc.pCmdTail = uti596_softc.scb.pCmd = pCmd; + + UTI_WAIT_COMMAND_ACCEPTED(10000,"Add Polled command: wait prev"); /* ensure prev command complete */ + + uti596_softc.scb.command = CUC_START; + outport_word (CHAN_ATTN,0); + + UTI_WAIT_COMMAND_ACCEPTED(2000000,"Add Polled command: start"); /* ensure previous command complete */ + /* if ( !(pCmd -> status & STAT_C ) ){ + printf("****FAILED poll command\n"); + } + */ + uti596_softc.pCmdHead = uti596_softc.pCmdTail = uti596_softc.scb.pCmd = I596_NULL; + +#ifdef DBG_596 + printf("Scb status & command 0x%x 0x%x\n", + uti596_softc.scb.status, + uti596_softc.scb.command ); +#endif + + } +/* + * Driver transmit daemon + */ +void +uti596_txDaemon (void *arg) +{ + struct uti596_softc *sc = (struct uti596_softc *)arg; + struct ifnet *ifp = &sc->arpcom.ac_if; + struct mbuf *m; + rtems_event_set events; + + for (;;) { + /* + * Wait for packet from stack + */ + rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, + RTEMS_EVENT_ANY | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, &events); + + /* + * Send packets till queue is empty + */ + for (;;) { + /* + * Get the next mbuf chain to transmit. + */ + IF_DEQUEUE(&ifp->if_snd, m); + if (!m) + break; + + send_packet (ifp, m); /* blocks */ + } + ifp->if_flags &= ~IFF_OACTIVE; /* no more to send, mark output inactive */ + } +} + + + /*********************************************************************** + * Function: send_packet + * + * Description: Send a raw ethernet packet + * + * Algorithm: + * increment some stats counters, + * create the transmit command, + * add the command to the CBL, + * wait for event + * + ***********************************************************************/ + +void send_packet(struct ifnet *ifp, struct mbuf *m) +{ + struct i596_tbd *pPrev = I596_NULL, + *pRemainingTbdList, + *pTbd; + struct mbuf *n, *input_m = m; + + struct uti596_softc *sc = ifp->if_softc; /* is this available from ifp ?*/ + + struct mbuf *l = NULL; + unsigned int length = 0; + rtems_status_code status; + int bd_count = 0; + rtems_event_set events; + + /* + * Block all competing threads. IS THIS NOW NEEDED? I THINK NOT + */ + + /* while(1) { +#ifdef DBG_RAW + rtems_task_ident (0, 0, &tid); + printf("0x%x Waiting for semaphore\n", tid); +#endif + status = rtems_semaphore_obtain(sc->semaphore_id, + RTEMS_WAIT, + RTEMS_NO_TIMEOUT); + + if ( status == RTEMS_SUCCESSFUL ){ +#ifdef DBG_RAW + printf("0x%x Got semaphore\n", tid); +#endif + break; + } + else + { +#ifdef DBG_RAW + printf("0x%x Waits on semaphore\n", tid); +#endif + sc->txRawWait++; + } + } + */ + /* + * For all mbufs in the chain, + * fill a transmit buffer descriptor + */ + pTbd = sc->pTxCmd->pTbd; + + do { + if (m->m_len) { + /* + * Fill in the buffer descriptor + */ + length += m->m_len; + pTbd->data = mtod (m, void *); + pTbd->size = m->m_len; + pPrev = pTbd; + pTbd = pTbd -> next; + l = m; + m = m->m_next; + } + else { + /* + * Just toss empty mbufs + */ + MFREE (m, n); + m = n; + if (l != NULL) + l->m_next = m; + } + } while( m != NULL && ++bd_count < 16 ); + + + /* This should never happen */ + if ( bd_count == 16 ) { + printf("TX ERROR:Too many mbufs in the packet!!!\n"); + printf("Must coalesce!\n"); + } + + + if ( length < UTI_596_ETH_MIN_SIZE ) { + pTbd->data = sc->zeroes; /* add padding to pTbd */ + pTbd->size = UTI_596_ETH_MIN_SIZE - length; /* zeroes have no effect on the CRC */ + } + else + pTbd = pPrev; /* Don't use pTbd in the send routine */ + + /* Disconnect the packet from the list of Tbd's */ + pRemainingTbdList = pTbd->next; + pTbd->next = I596_NULL; + pTbd->size |= UTI_596_END_OF_FRAME; + +#ifdef DBG_RAW + printf("RAW:Add cmd and sleep\n"); +#endif + + sc->rawsndcnt++; + +#ifdef DBG_RAW + printf ("sending packet\n"); +#endif + + /* Sending Zero length packet: shouldn't happen */ + if (pTbd->size <= 0) return ; + + +#ifdef DEBUG_INIT_2 + printf("\nTransmitter adds packet\n"); + print_hdr ( sc->pTxCmd->pTbd->data ); /* print the first part */ + print_pkt ( sc->pTxCmd->pTbd->next->data ); /* print the first part */ + /* print_echo(sc->pTxCmd->pTbd->data); */ +#endif +#ifdef DBG_VERSION + BREAKPOINT(); +#endif + + + /* add the command to the output command queue */ + uti596addCmd ( (struct i596_cmd *) sc->pTxCmd ); + + /* sleep until the command has been processed or Timeout encountered. */ + status= rtems_bsdnet_event_receive (INTERRUPT_EVENT, + RTEMS_WAIT|RTEMS_EVENT_ANY, + RTEMS_NO_TIMEOUT, + &events); + + if ( status != RTEMS_SUCCESSFUL ) { + printf("Could not sleep %s\n", rtems_status_text(status)); + } + +#ifdef DBG_RAW + printf("RAW: wake\n"); +#endif + + sc->txInterrupts++; + +#ifdef DEBUG_INIT + printf("\nTransmitter issued packet\n"); + print_hdr ( sc->pTxCmd->pTbd -> data ); /* print the first part */ + print_pkt ( sc->pTxCmd->pTbd ->next-> data ); /* print the first part */ +#endif + + if ( sc->pTxCmd -> cmd.status & STAT_OK ) + sc->stats.tx_packets++; + else + { +#ifdef DBG_RAW + printf("******Driver Error 0x%x\n", sc->pTxCmd -> cmd.status ); +#endif + sc->stats.tx_errors++; + if ( sc->pTxCmd->cmd.status & 0x0020 ) + sc->stats.tx_retries_exceeded++; + if (!(sc->pTxCmd->cmd.status & 0x0040)) + sc->stats.tx_heartbeat_errors++; + if ( sc->pTxCmd->cmd.status & 0x0400 ) + sc->stats.tx_carrier_errors++; + if ( sc->pTxCmd->cmd.status & 0x0800 ) + sc->stats.collisions++; + if ( sc->pTxCmd->cmd.status & 0x1000 ) + sc->stats.tx_aborted_errors++; + } /* end if stat_ok */ + + /* + * Restore the transmited buffer descriptor chain. + */ + pTbd -> next = pRemainingTbdList; + + /* + * Free the mbufs used by the sender. + */ + m = input_m; + while ( m != NULL ) { + MFREE(m,n); + m = n; + } + + /* We have finished with this critical section */ + /* rtems_semaphore_release(sc->semaphore_id); */ + +} + + /*********************************************************************** + * Function: print_eth + * + * Description: + * Print the contents of an ethernet packet header + * CANNOT BE CALLED FROM ISR + * + * Algorithm: + * Print Destination, Src, and type of packet + * + ***********************************************************************/ + + /* static */ void print_eth(unsigned char *add) + { + int i; + short int length; + + printf("Packet Location %p\n", add); + + printf ("Dest "); + + for (i = 0; i < 6; i++) + printf(" %2.2X", add[i]); + + printf ("\n"); + + printf ("Source"); + + for (i = 6; i < 12; i++) + printf(" %2.2X", add[i]); + + printf ("\n"); + + printf ("frame type %2.2X%2.2X\n", add[12], add[13]); + + if ( add[12] == 0x08 && add[13] == 0x06 ) + { /* an ARP */ + printf("Hardware type : %2.2X%2.2X\n", add[14],add[15]); + printf("Protocol type : %2.2X%2.2X\n", add[16],add[17]); + printf("Hardware size : %2.2X\n", add[18]); + printf("Protocol size : %2.2X\n", add[19]); + printf("op : %2.2X%2.2X\n", add[20],add[21]); + + printf("Sender Enet addr: "); + + for ( i=0; i< 5 ; i++) + printf( "%x:", add[22 + i]); + + printf("%x\n", add[27]); + + printf("Sender IP addr: "); + for ( i=0; i< 3 ; i++) + printf( "%u.", add[28 + i]); + + printf("%u\n", add[31]); + + printf("Target Enet addr: "); + for ( i=0; i< 5 ; i++) + printf( "%x:", add[32 + i]); + printf("%x\n", add[37]); + + printf("Target IP addr: "); + + for ( i=0; i< 3 ; i++) + printf( "%u.", add[38 + i]); + printf("%u\n", add[41]); + + } + + if ( add[12] == 0x08 && add[13] == 0x00 ) + { /* an IP packet */ + printf("*********************IP HEADER******************\n"); + printf("IP version/IPhdr length: %2.2X TOS: %2.2X\n", add[14] , add[15]); + printf("IP total length: %2.2X %2.2X, decimal %d\n", add[16], add[17], length = (add[16]<<8 | add[17] )); + printf("IP identification: %2.2X %2.2X, 3-bit flags and offset %2.2X %2.2X\n", + add[18],add[19], add[20], add[21]); + printf("IP TTL: %2.2X, protocol: %2.2X, checksum: %2.2X %2.2X \n", + add[22],add[23],add[24],add[25]); + printf("IP packet type: %2.2X code %2.2X\n", add[34],add[35]); + + printf("Source IP address: "); + for ( i=0; i< 3 ; i++) + printf( "%u.", add[26 + i]); + + printf("%u\n", add[29]); + + printf("Destination IP address: "); + for ( i=0; i< 3 ; i++) + printf( "%u.", add[30 + i]); + printf("%u\n", add[33]); + + /* printf("********************IP Packet Data*******************\n"); + length -=20; + for ( i=0; i < length ; i++) + printf("0x%2.2x ", add[34+i]); + printf("\n"); + + printf("ICMP checksum: %2.2x %2.2x\n", add[36], add[37]); + printf("ICMP identifier: %2.2x %2.2x\n", add[38], add[39]); + printf("ICMP sequence nbr: %2.2x %2.2x\n", add[40], add[41]); + */ + } + + + } +#ifdef DEBUG_INIT + + /*********************************************************************** + * Function: print_eth + * + * Description: + * Print the contents of an ethernet packet header + * CANNOT BE CALLED FROM ISR + * + * Algorithm: + * Print Destination, Src, and type of packet + * + ***********************************************************************/ + + /* static */ void print_hdr(unsigned char *add) + { + int i; + short int length; + + printf("Header Location %p\n", add); + + printf ("Dest "); + + for (i = 0; i < 6; i++) + printf(" %2.2X", add[i]); + + printf ("\n"); + + printf ("Source"); + + for (i = 6; i < 12; i++) + printf(" %2.2X", add[i]); + + printf ("\n"); + + printf ("frame type %2.2X%2.2X\n", add[12], add[13]); + + + } + /*********************************************************************** + * Function: print_pkt + * + * Description: + * Print the contents of an ethernet packet header + * CANNOT BE CALLED FROM ISR + * + * Algorithm: + * Print Destination, Src, and type of packet + * + ***********************************************************************/ + + /* static */ void print_pkt(unsigned char *add) + { + int i; + short int length; + + printf("Data Location %p\n", add); + + if ( add[0] == 0x08 && add[1] == 0x06 ) + { /* an ARP */ + printf("Hardware type : %2.2X%2.2X\n", add[14],add[15]); + printf("Protocol type : %2.2X%2.2X\n", add[16],add[17]); + printf("Hardware size : %2.2X\n", add[18]); + printf("Protocol size : %2.2X\n", add[19]); + printf("op : %2.2X%2.2X\n", add[20],add[21]); + + printf("Sender Enet addr: "); + + for ( i=0; i< 5 ; i++) + printf( "%x:", add[22 + i]); + + printf("%x\n", add[27]); + + printf("Sender IP addr: "); + for ( i=0; i< 3 ; i++) + printf( "%u.", add[28 + i]); + + printf("%u\n", add[31]); + + printf("Target Enet addr: "); + for ( i=0; i< 5 ; i++) + printf( "%x:", add[32 + i]); + printf("%x\n", add[37]); + + printf("Target IP addr: "); + + for ( i=0; i< 3 ; i++) + printf( "%u.", add[38 + i]); + printf("%u\n", add[41]); + + } + + if ( add[0] == 0x08 && add[1] == 0x00 ) + { /* an IP packet */ + printf("*********************IP HEADER******************\n"); + printf("IP version/IPhdr length: %2.2X TOS: %2.2X\n", add[14] , add[15]); + printf("IP total length: %2.2X %2.2X, decimal %d\n", add[16], add[17], length = (add[16]<<8 | add[17] )); + printf("IP identification: %2.2X %2.2X, 3-bit flags and offset %2.2X %2.2X\n", + add[18],add[19], add[20], add[21]); + printf("IP TTL: %2.2X, protocol: %2.2X, checksum: %2.2X %2.2X \n", + add[22],add[23],add[24],add[25]); + printf("IP packet type: %2.2X code %2.2X\n", add[34],add[35]); + + printf("Source IP address: "); + for ( i=0; i< 3 ; i++) + printf( "%u.", add[26 + i]); + + printf("%u\n", add[29]); + + printf("Destination IP address: "); + for ( i=0; i< 3 ; i++) + printf( "%u.", add[30 + i]); + printf("%u\n", add[33]); + + printf("********************IP Packet Data*******************\n"); + length -=20; + for ( i=0; i < length ; i++) + printf("0x%2.2x ", add[34+i]); + printf("\n"); + + printf("ICMP checksum: %2.2x %2.2x\n", add[36], add[37]); + printf("ICMP identifier: %2.2x %2.2x\n", add[38], add[39]); + printf("ICMP sequence nbr: %2.2x %2.2x\n", add[40], add[41]); + } + + + } + /*********************************************************************** + * Function: print_echo + * + * Description: + * Print the contents of an ethernet packet header + * CANNOT BE CALLED FROM ISR + * + * Algorithm: + * Prints only echo packets + * + ***********************************************************************/ + + /* static */ void print_echo(unsigned char *add) + { + int i; + short int length; + + if ( add[12] == 0x08 && add[13] == 0x00 ){ /* an IP packet */ + + printf("Packet Location %p\n", add); + + printf ("Dest "); + + for (i = 0; i < 6; i++) + printf(" %2.2X", add[i]); + + printf ("\n"); + + printf ("Source"); + + for (i = 6; i < 12; i++) + printf(" %2.2X", add[i]); + + printf ("\n"); + + printf ("frame type %2.2X%2.2X\n", add[12], add[13]); + + printf("*********************IP HEADER******************\n"); + printf("IP version/IPhdr length: %2.2X TOS: %2.2X\n", add[14] , add[15]); + printf("IP total length: %2.2X %2.2X, decimal %d\n", add[16], add[17], length = (add[16]<<8 | add[17] )); + printf("IP identification: %2.2X %2.2X, 3-bit flags and offset %2.2X %2.2X\n", + add[18],add[19], add[20], add[21]); + printf("IP TTL: %2.2X, protocol: %2.2X, checksum: %2.2X %2.2X \n", + add[22],add[23],add[24],add[25]); + printf("IP packet type: %2.2X code %2.2X\n", add[34],add[35]); + + printf("Source IP address: "); + for ( i=0; i< 3 ; i++) + printf( "%u.", add[26 + i]); + + printf("%u\n", add[29]); + + printf("Destination IP address: "); + for ( i=0; i< 3 ; i++) + printf( "%u.", add[30 + i]); + printf("%u\n", add[33]); + + printf("********************IP Packet Data*******************\n"); + length -=20; + for ( i=0; i < length ; i++) + printf("0x%2.2x ", add[34+i]); + printf("\n"); + + printf("ICMP checksum: %2.2x %2.2x\n", add[36], add[37]); + printf("ICMP identifier: %2.2x %2.2x\n", add[38], add[39]); + printf("ICMP sequence nbr: %2.2x %2.2x\n", add[40], add[41]); + } + } +#endif + + /*********************************************************************** + * Function: uti596_attach + * + * Description: + * User requested attach of driver to hardware + * + * Algorithm: + * + * Check that the board is present + * parse and store the command line parameters + * argv[0]: interface label, e.g., "uti596" + * argv[1]: maximum transmission unit, bytes, e.g., "1500" + * argv[2]: IP address (optional) + * initialize required rx and tx buffers + * hook interrupt + * issue start command and some diagnostics + * return + * + ***********************************************************************/ + + +int uti596_attach(struct rtems_bsdnet_ifconfig * pConfig ) +{ + struct uti596_softc *sc = &uti596_softc; /* soft config */ + struct ifnet * ifp = &sc->arpcom.ac_if; + int i = 0; + +#ifdef DBG_ATTACH + printf("attach"); +#endif + + + sc->started = 0; /* The NIC is not started yet */ + sc->ioAddr = IO_ADDR; + + /* Indicate to ULCS that this is initialized */ + ifp->if_softc = sc; + + /* Assign the name */ + ifp->if_name = "uti"; + + /* Assign the unit number */ + ifp->if_unit = 1; + + /* Assign mtu */ + if ( pConfig -> mtu ) + ifp->if_mtu = pConfig -> mtu; + else + ifp->if_mtu = ETHERMTU; + + /* Assign and possibly override the hw address */ + + if ( !pConfig->hardware_address) { /* Read the ethernet address from the board */ + for (i = 0; i < 8; i++) + inport_byte(NIC_ADDR+i,sc->arpcom.ac_enaddr[i] ); + } + else { + /* hwaddr override */ + memcpy (sc->arpcom.ac_enaddr, pConfig->hardware_address, ETHER_ADDR_LEN); + } + + /* Test for valid hwaddr */ + if(memcmp(sc->arpcom.ac_enaddr,"\xAA\x55\x01",3)!= 0)/* b0 of byte 0 != 0 => multicast */ + return ENODEV; + + /* Assign requested receive buffer descriptor count */ + if (pConfig->rbuf_count) + sc->rxBdCount = pConfig->rbuf_count; + else + sc->rxBdCount = RX_BUF_COUNT; + + /* Assign requested tx buffer descriptor count */ + if (pConfig->xbuf_count) + sc->txBdCount = pConfig->xbuf_count; + else + sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF; + + /* ignore_broadcast is an unused feature... accept broadcast */ + /* sc->acceptBroadcast = !pConfig->ignore_broadcast; */ + + ifp->if_snd.ifq_maxlen = ifqmaxlen; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; + + /* to init_hardware */ + sc->started = 1; + sc->pInboundFrameQueue = I596_NULL; + + + ifp->if_ioctl = uti596_ioctl; + ifp->if_init = uti596_init; + ifp->if_start = uti596_start; + ifp->if_output = ether_output; + + sc->scb.command = 0; + + /* + * Attach the interface + */ + if_attach (ifp); + ether_ifattach (ifp); + return 1; + + } + + /*********************************************************************** + * Function: uti596DynamicInterruptHandler + * + * Description: + * This is the interrupt handler for the uti596 board + * + * Algorithm: + * + ***********************************************************************/ + + /* static */ rtems_isr uti596DynamicInterruptHandler(rtems_vector_number irq) + { +#ifdef DEBUG_ISR + printk("I"); +#endif + + UTI_WAIT_COMMAND_ACCEPTED(20000, "****ERROR:on ISR entry"); + + scbStatus = uti596_softc.scb.status & 0xf000; + + if ( scbStatus ){ + /* acknowledge interrupts */ + /* printk("***INFO: ACK %x\n", scbStatus);*/ + uti596_softc.scb.command = scbStatus; + outport_word(CHAN_ATTN, 0); + + if( uti596_softc.resetDone ) { + /* stack is attached */ + UTI_WAIT_COMMAND_ACCEPTED(20000, "****ERROR:ACK"); + } + else { + printk("\n***INFO:ISR won't wait\n"); + return; + } + } + else { + printk("\n***WARNING: Nothing to ACK\n"); + return; + } + + if ( (scbStatus & SCB_STAT_CX) && !(scbStatus & SCB_STAT_CNA) ) + printk("\n*****ERROR:Command Complete, CNA available: %#x\n", scbStatus); + + if ( !(scbStatus & SCB_STAT_CX) && (scbStatus & SCB_STAT_CNA) ) + printk("\n*****ERROR: CNA went unavailable, NO CX:%#x\n",scbStatus); + + if ( scbStatus & SCB_STAT_RNR ) + printk("\n*****WARNING: RNR %x\n",scbStatus); + + /* + * Receive Unit Control + */ + if ( scbStatus & SCB_STAT_FR ) { /* a frame has been received */ + uti596_softc.rxInterrupts++; + +#ifdef DBG_FR + printk("\nISR:FR\n"); +#endif + if ( uti596_softc.pBeginRFA == I596_NULL || !( uti596_softc.pBeginRFA -> stat & STAT_C ) || + forceResetRX ) { + + /* if ( !forceResetRX ) + printk("****ERROR: FR interrupt and NO complete FR!\n"); + else + printk("****INFO: RX reset requested\n"); + */ + forceResetRX = 0; + printk("****INFO: Resetting board ( rx ) commented out\n"); + dump_scb(); + /* uti596reset(); */ + } + else + while ( uti596_softc.pBeginRFA != I596_NULL && + ( uti596_softc.pBeginRFA -> stat & STAT_C)) { + +#ifdef DBG_ISR + printk("ISR:pBeginRFA != NULL\n"); +#endif + count_rx ++; + if ( count_rx > 1) + printk("****WARNING: Received 2 frames on 1 interrupt \n"); + + /* + * Give Received Frame to the ULCS + */ + uti596_softc.countRFD--; + + if ( uti596_softc.countRFD < 0 ) + printk("Count < 0 !!!: count == %d, beginRFA = %p\n", + uti596_softc.countRFD, uti596_softc.pBeginRFA); + + uti596_softc.stats.rx_packets++; + pIsrRfd = uti596_softc.pBeginRFA -> next; /* the append destroys the link */ + uti596append( &uti596_softc.pInboundFrameQueue , uti596_softc.pBeginRFA ); + + /* + * if we have just received the a frame int he last unknown RFD, + * then it is certain that the RFA is empty. + */ + if ( uti596_softc.pLastUnkRFD == uti596_softc.pBeginRFA ) { + UTI_596_ASSERT(uti596_softc.pLastUnkRFD != I596_NULL,"****ERROR:LastUnk is NULL, begin ptr @ end!\n"); + uti596_softc.pEndRFA = uti596_softc.pLastUnkRFD = I596_NULL; + } + +#ifdef DBG_ISR + printk("Wake %#x\n",uti596_softc.rxDaemonTid); +#endif + sc = rtems_event_send(uti596_softc.rxDaemonTid, INTERRUPT_EVENT); + if ( sc != RTEMS_SUCCESSFUL ) + rtems_panic ("Can't notify rxDaemon: %s\n", + rtems_status_text (sc)); +#ifdef DBG_RAW_ISR + else + printk("Rx Wake: %#x\n",uti596_softc.rxDaemonTid); +#endif + + uti596_softc.pBeginRFA = pIsrRfd; + } /* end while */ + + if ( uti596_softc.pBeginRFA == I596_NULL ){ /* adjust the pEndRFA to reflect an empty list */ + if ( uti596_softc.pLastUnkRFD == I596_NULL && uti596_softc.countRFD != 0 ) + printk("Last Unk is NULL, BeginRFA is null, and count == %d\n",uti596_softc.countRFD); + + uti596_softc.pEndRFA = I596_NULL; + if ( uti596_softc.countRFD != 0 ) { + printk("****ERROR:Count is %d, but begin ptr is NULL\n",uti596_softc.countRFD ); + dumpQ(); + } + } + + } /* end scb_stat_fr */ + + /* + * Check For Command Complete + */ + if ( scbStatus & SCB_STAT_CX ){ +#ifdef DBG_ISR + printk("ISR:CU\n"); +#endif + + pIsrCmd = uti596_softc.pCmdHead; + + /* + * For ALL completed commands + */ + if ( pIsrCmd != I596_NULL && pIsrCmd->status & STAT_C && !forceResetTX ){ + +#ifdef DBG_RAW_ISR + printk("ISR:pIsrCmd != NULL\n"); +#endif + + /* + * Adjust the drivers command block list + */ + uti596_softc.pCmdHead = pIsrCmd -> next; + + /* + * If there are MORE commands to process, + * the serialization in the raw routine has failed. + * ( Perhaps AddCmd is bad? ) + */ + UTI_596_ASSERT(uti596_softc.pCmdHead == I596_NULL, + "****ERROR: command serialization failed\n"); + /* + * What if the command did not complete OK? + */ + switch ( pIsrCmd->command & 0x7) + { + case CmdConfigure: + + /* printk("****INFO:Configure OK\n"); */ + uti596_softc.cmdOk = 1; + break; + + case CmdDump: + +#ifdef DBG_ISR + printk("dump!\n"); +#endif + uti596_softc.cmdOk = 1; + break; + + case CmdDiagnose: + +#ifdef DBG_ISR + printk("diagnose!\n"); +#endif + uti596_softc.cmdOk = 1; + break; + + case CmdSASetup: + + /* printk("****INFO:Set address interrupt\n"); */ + if ( pIsrCmd -> status & STAT_OK ) + uti596_softc.cmdOk = 1; + else + printk("****ERROR:SET ADD FAILED\n"); + break; + + case CmdTx: + { + UTI_596_ASSERT(uti596_softc.txDaemonTid, "****ERROR:Null txDaemonTid\n"); +#ifdef DBG_ISR + printk("wake TX:0x%x\n",uti596_softc.txDaemonTid); +#endif + if ( uti596_softc.txDaemonTid ){ /* Ensure that the transmitter is waiting */ + sc = rtems_event_send (uti596_softc.txDaemonTid, + INTERRUPT_EVENT); + + if ( sc != RTEMS_SUCCESSFUL ) + printk("****ERROR:Could NOT send event to tid 0x%x : %s\n", + uti596_softc.txDaemonTid, rtems_status_text (sc) ); +#ifdef DBG_RAW_ISR + else + printk("****INFO:Tx wake: %#x\n",uti596_softc.txDaemonTid); +#endif + } + } /* End case Cmd_Tx */ + break; + + case CmdMulticastList: + + printk("***ERROR:Multicast?!\n"); + pIsrCmd->next = I596_NULL; + break; + + case CmdTDR: + { + unsigned long status = *( (unsigned long *)pIsrCmd)+1; + printk("****ERROR:TDR?!\n"); + + if (status & STAT_C) + { + /* + * mark the TDR command successful + */ + uti596_softc.cmdOk = 1; + } + else + { + if (status & 0x4000) + printk("****WARNING:Transceiver problem.\n"); + if (status & 0x2000) + printk("****WARNING:Termination problem.\n"); + if (status & 0x1000) + printk("****WARNING:Short circuit.\n"); + + /* printk("****INFO:Time %ld.\n", status & 0x07ff); */ + } + } + break; + + default: + /* + * This should never be reached + */ + printk("CX but NO known command\n"); + } /* end switch */ + pIsrCmd = uti596_softc.pCmdHead; /* next command */ + if ( pIsrCmd != I596_NULL ) + printk("****WARNING: more commands in list, but no start to NIC\n"); + } /* end if completed */ + else { + + /* if ( !forceResetTX ) + printk("*****ERROR:CX but no command is completed\n"); + else + printk("*****INFO:forcing an ethernet card reset\n"); + */ + /* Reset the ethernet card, and wake the transmitter (if necessary) */ + + printk("****INFO: Resetting board ( tx )\n"); + forceResetTX = 0; + uti596reset(); + if ( uti596_softc.txDaemonTid){ /* Ensure that a transmitter is waiting */ + /* printk("*****INFO:Wake Transmitter\n"); */ + sc = rtems_event_send (uti596_softc.txDaemonTid, + INTERRUPT_EVENT); + + if ( sc != RTEMS_SUCCESSFUL ) + printk("****ERROR:Could NOT send event to tid 0x%x : %s\n",uti596_softc.txDaemonTid, rtems_status_text (sc) ); +#ifdef DBG_RAW_ISR + else + printk("****INFO:Tx wake: %#x\n",uti596_softc.txDaemonTid); +#endif + } + } + } /* end if command complete */ + + + /* if the receiver has stopped, + * check if this is a No Resources scenario, + * Try to add more RFD's ( no RBDs are used ) + */ + if ( uti596_softc.started ) { + if ( scbStatus & SCB_STAT_RNR ){ +#ifdef DBG_ISR + printk("INFO:RNR: status %#x \n", uti596_softc.scb.status ); +#endif + /* + * THE RECEIVER IS OFF! + */ + if ( uti596_softc.pLastUnkRFD != I596_NULL ){ /* We have an unknown RFD, it is not inbound*/ + if ( uti596_softc.pLastUnkRFD -> stat & (STAT_C | STAT_B )) /* in use */ + uti596_softc.pEndRFA = uti596_softc.pLastUnkRFD; /* update end */ + else { + /* + * It is NOT in use, and since RNR, we know EL bit of pEndRFA was read! + * So, unlink it from the RFA and move it to the saved queue. + * But pBegin can equal LastUnk! + */ + + if ( uti596_softc.pEndRFA != I596_NULL ){ /* check added feb24. */ +#ifdef DEBUG_RFA + if (uti596_softc.pEndRFA -> next != uti596_softc.pLastUnkRFD){ + printk("***ERROR:UNK: %p not end->next: %p, end: %p\n", + uti596_softc.pLastUnkRFD,uti596_softc.pEndRFA -> next,uti596_softc.pEndRFA); + dumpQ(); + printk("***INFO:countRFD now %d\n", uti596_softc.countRFD); + printk("\n\n"); + + } +#endif + uti596_softc.pEndRFA -> next = I596_NULL; /* added feb 16 */ + } + uti596append( &uti596_softc.pSavedRfdQueue, uti596_softc.pLastUnkRFD ); + uti596_softc.savedCount++; + uti596_softc.pEndSavedQueue = uti596_softc.pLastUnkRFD; + uti596_softc.countRFD--; /* It was not in the RFA */ + /* + * The Begin pointer CAN advance this far. We must resynch the CPU side + * with the chip. + */ + if ( uti596_softc.pBeginRFA == uti596_softc.pLastUnkRFD ) { +#ifdef DEBUG_RFA + if ( uti596_softc.countRFD != 0 ) { + printk("****INFO:About to set begin to NULL, with count == %d\n", uti596_softc.countRFD ); + dumpQ(); + printk("\n\n"); + } +#endif + uti596_softc.pBeginRFA = I596_NULL; + UTI_596_ASSERT(uti596_softc.countRFD == 0,"****ERROR:Count must be zero here!\n"); + } + } + + uti596_softc.pLastUnkRFD = I596_NULL; + + } /* end if exists UnkRFD */ + + /* + * Append the saved queue to the RFA. + * Any further RFD's being supplied will be added to + * this new list. + */ + if ( uti596_softc.pSavedRfdQueue != I596_NULL ) { /* entries to add */ + if ( uti596_softc.pBeginRFA == I596_NULL ) { /* add at beginning to list */ +#ifdef DEBUG_RFA + if(uti596_softc.countRFD != 0) { + printk("****ERROR:Begin pointer is NULL, but count == %d\n",uti596_softc.countRFD); + dumpQ(); + } +#endif + uti596_softc.pBeginRFA = uti596_softc.pSavedRfdQueue; + uti596_softc.pEndRFA = uti596_softc.pEndSavedQueue; + uti596_softc.pSavedRfdQueue = uti596_softc.pEndSavedQueue = I596_NULL; /* Reset the End */ + } + else { +#ifdef DEBUG_RFA + if ( uti596_softc.countRFD <= 0) { + printk("****ERROR:Begin pointer is not NULL, but count == %d\n",uti596_softc.countRFD); + dumpQ(); + } +#endif + UTI_596_ASSERT( uti596_softc.pEndRFA != I596_NULL, "****WARNING: END RFA IS NULL\n"); + UTI_596_ASSERT( uti596_softc.pEndRFA->next == I596_NULL, "****ERROR:END RFA -> next must be NULL\n"); + + uti596_softc.pEndRFA->next = uti596_softc.pSavedRfdQueue; + uti596_softc.pEndRFA->cmd &= ~CMD_EOL; /* clear the end of list */ + uti596_softc.pEndRFA = uti596_softc.pEndSavedQueue; + uti596_softc.pSavedRfdQueue = uti596_softc.pEndSavedQueue = I596_NULL; /* Reset the End */ +#ifdef DEBUG_ISR + printk("count: %d, saved: %d \n", uti596_softc.countRFD , uti596_softc.savedCount); +#endif + + } + /* printk("Isr: countRFD = %d\n",uti596_softc.countRFD); */ + uti596_softc.countRFD += uti596_softc.savedCount; + /* printk("Isr: after countRFD = %d\n",uti596_softc.countRFD); */ + uti596_softc.savedCount = 0; + } + + +#ifdef DBG_596_RFD + printk("The list starts here %p\n",uti596_softc.pBeginRFA ); +#endif + + if ( uti596_softc.countRFD > 1 && /* there is at least TWO */ + !( uti596_softc.pBeginRFA -> stat & (STAT_C | STAT_B ))) { /* restart when not in use !! */ + + UTI_596_ASSERT(uti596_softc.scb.command == 0, "****ERROR:scb command must be zero\n"); + uti596_softc.scb.pRfd = uti596_softc.pBeginRFA; + /* start RX here */ + printk("****INFO: ISR Starting receiver\n"); + uti596_softc.scb.command = RX_START; /* should this also be CU start? */ + outport_word(CHAN_ATTN, 0); + } + else { + printk("****WARNING: Receiver NOT Started -- countRFD = %d\n", uti596_softc.countRFD); + printk("82596 cmd: 0x%x, status: 0x%x RFA len: %d\n", + uti596_softc.scb.command, + uti596_softc.scb.status, + uti596_softc.countRFD); + + printk("\nRFA: \n"); + for ( pISR_Rfd = uti596_softc.pBeginRFA; + pISR_Rfd != I596_NULL; + pISR_Rfd = pISR_Rfd->next) + printk("Frame @ %p, status: %2.2x, cmd: %2.2x\n", + pISR_Rfd, pISR_Rfd->stat, pISR_Rfd->cmd); + + printk("\nInbound: \n"); + for ( pISR_Rfd = uti596_softc.pInboundFrameQueue; + pISR_Rfd != I596_NULL; + pISR_Rfd = pISR_Rfd->next) + printk("Frame @ %p, status: %2.2x, cmd: %2.2x\n", + pISR_Rfd, pISR_Rfd->stat, pISR_Rfd->cmd); + + + printk("\nSaved: \n"); + for ( pISR_Rfd = uti596_softc.pSavedRfdQueue; + pISR_Rfd != I596_NULL; + pISR_Rfd = pISR_Rfd->next) + printk("Frame @ %p, status: %2.2x, cmd: %2.2x\n", + pISR_Rfd, pISR_Rfd->stat, pISR_Rfd->cmd); + printk("\nUnknown: %p\n",uti596_softc.pLastUnkRFD); + } + } /* end stat_rnr */ + + } /* end if receiver started */ + UTI_596_ASSERT(uti596_softc.scb.status == scbStatus, "****WARNING:scbStatus change!\n"); + +#ifdef DBG_ISR + printk("X\n"); +#endif + count_rx=0; + return; + } + + +/*********************************************************************** + * Function: void uti596dequeue + * + * Description: + * removes an RFD from the received frame queue, + * + * Algorithm: + * + ***********************************************************************/ + +struct i596_rfd * uti596dequeue( struct i596_rfd ** ppQ ) + { + ISR_Level level; + + struct i596_rfd * pRfd; + _ISR_Disable(level); + + /* invalid address, or empty queue or emptied queue */ + if( ppQ == NULL || *ppQ == NULL || *ppQ == I596_NULL) { + _ISR_Enable(level); + return I596_NULL; + } + + pRfd = *ppQ; /* The dequeued buffer */ + *ppQ = pRfd->next; /* advance the queue pointer */ + pRfd->next = I596_NULL; /* unlink the rfd being returned */ + + + _ISR_Enable(level); + return pRfd; +} + +/*********************************************************************** + * Function: void uti596append + * + * Description: + * adds an RFD to the end of the received frame queue, + * for processing by the rxproc. + * Also removes this RFD from the RFA + * + * Algorithm: + * + ***********************************************************************/ + +void uti596append( struct i596_rfd ** ppQ , struct i596_rfd * pRfd ) +{ + + struct i596_rfd *p; + + if ( pRfd != NULL && pRfd != I596_NULL) { + pRfd -> next = I596_NULL; + pRfd -> cmd |= CMD_EOL; /* set EL bit */ + + if ( *ppQ == NULL || *ppQ == I596_NULL ) { + /* Empty or emptied */ + *ppQ = pRfd; + } + else + { + for ( p=*ppQ; p -> next != I596_NULL; p=p->next) + ; + + p->cmd &= ~CMD_EOL; /* Clear EL bit at end */ + p->next = pRfd; + } + } + else + printf("Illegal attempt to append: %p\n", pRfd); +} + + +/*********************************************************************** + * Function: uti596stop + * + * Description: + * stop the driver + * + * Algorithm: + * mark driver as not started, + * mark transmitter as busy + * abort any transmissions/receptions + * clean-up all buffers ( RFD's et. al. ) + * + * + * + * + ***********************************************************************/ + + +/* static */ +void uti596_stop(struct uti596_softc *sc) +{ + sc->started = 0; + +#ifdef DBG_596 + printf("%s: Shutting down ethercard, status was %4.4x.\n", + uti596_softc.pIface->name, uti596_softc.scb.status); +#endif + + printf("Stopping interface\n"); + sc->scb.command = CUC_ABORT|RX_ABORT; + outport_word( CHAN_ATTN, 0 ); + + +} + + +static int +uti596_ioctl (struct ifnet *ifp, int command, caddr_t data) +{ + struct uti596_softc *sc = ifp->if_softc; + int error = 0; + + switch (command) { + case SIOCGIFADDR: + case SIOCSIFADDR: + printk("SIOCSIFADDR\n"); + ether_ioctl (ifp, command, data); + break; + + case SIOCSIFFLAGS: + printk("SIOCSIFFLAGS\n"); + switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { + case IFF_RUNNING: + printk("IFF_RUNNING\n"); + uti596_stop (sc); + break; + + case IFF_UP: + printk("IFF_UP\n"); + uti596_init (sc); + break; + + case IFF_UP | IFF_RUNNING: + printk("IFF_UP and RUNNING\n"); + uti596_stop (sc); + uti596_init (sc); + break; + + default: + printk("default\n"); + + break; + } + break; + + case SIO_RTEMS_SHOW_STATS: + printk("show stats\n"); + uti596_stats (sc); + break; + + /* + * FIXME: All sorts of multicast commands need to be added here! + */ + default: + printk("default: EINVAL\n"); + error = EINVAL; + break; + } + return error; +} + + +/*********************************************************************** + * Function: uti596_stats + * + * Description: + * print out the collected data + * + * Algorithm: + * use printf + * + ***********************************************************************/ + + +void +uti596_stats(struct uti596_softc *sc) + { + printf(" CPU Reports:\n"); + printf ("Tx raw send count:%-8lu", sc->rawsndcnt); + printf ("Rx Interrupts:%-8lu", sc->rxInterrupts); + printf ("Tx Interrupts:%-8lu\n", sc->txInterrupts); + printf ("Rx Packets:%-8u", sc->stats.rx_packets); + printf ("Tx Attempts:%-u\n", sc->stats.tx_packets); + + printf ("Rx Dropped:%-8u", sc->stats.rx_dropped); + printf ("Rx IP Packets:%-8u", sc->stats.rx_packets); + printf ("Tx Errors:%-8u\n", sc->stats.tx_errors); + printf ("Tx aborted:%-8u", sc->stats.tx_aborted_errors); + printf ("Tx Dropped:%-8u\n", sc->stats.tx_dropped); + printf ("Tx IP packets:%-8u", sc->stats.tx_packets); + + printf ("Collisions Detected:%-8u\n", sc->stats.collisions); + printf ("Tx Heartbeat Errors:%-8u", sc->stats.tx_heartbeat_errors); + printf ("Tx Carrier Errors:%-8u\n", sc->stats.tx_carrier_errors); + printf ("Tx Aborted Errors:%-8u", sc->stats.tx_aborted_errors); + printf ("Rx Length Errors:%-8u\n", sc->stats.rx_length_errors); + printf ("Rx Overrun Errors:%-8u", sc->stats.rx_over_errors); + printf ("Rx Fifo Errors:%-8u\n", sc->stats.rx_fifo_errors); + printf ("Rx Framing Errors:%-8u", sc->stats.rx_frame_errors); + printf ("Rx crc errors:%-8u\n", sc->stats.rx_crc_errors); + printf ("TX WAITS: %-8lu\n", sc->txRawWait); + + printf("NIC reports\n"); + dump_scb(); + } + +void dumpQ(void) { + + struct i596_rfd *pRfd; + + printf("savedQ:\n"); + for( pRfd = uti596_softc.pSavedRfdQueue; + pRfd != I596_NULL; + pRfd = pRfd -> next) + printf("pRfd: %p, stat: 0x%x cmd: 0x%x\n",pRfd,pRfd -> stat,pRfd -> cmd); + printf("Inbound:\n"); + for( pRfd = uti596_softc.pInboundFrameQueue; + pRfd != I596_NULL; + pRfd = pRfd -> next) + printf("pRfd: %p, stat: 0x%x cmd: 0x%x\n",pRfd,pRfd -> stat,pRfd -> cmd); + printf("Last Unk: %p\n", uti596_softc.pLastUnkRFD ); + + printf("RFA:\n"); + for( pRfd = uti596_softc.pBeginRFA; + pRfd != I596_NULL; + pRfd = pRfd -> next) + printf("pRfd: %p, stat: 0x%x cmd: 0x%x\n",pRfd,pRfd -> stat,pRfd -> cmd); +} + +void uti596Diagnose(int verbose){ + struct i596_cmd diagnose; + int count=10000; + + diagnose.command = CmdDiagnose; + diagnose.status = 0; + uti596addPolledCmd(&diagnose); + while( !( diagnose.status & STAT_C ) && count ) { + if(verbose) + printf("."); + count --; + } + if(verbose) + printf("Status diagnostic: 0x%2.2x\n", diagnose.status); + +} +void show_buffers (void) +{ + struct i596_rfd *pRfd; + + printf("82596 cmd: 0x%x, status: 0x%x RFA len: %d\n", + uti596_softc.scb.command, + uti596_softc.scb.status, + uti596_softc.countRFD); + + printf("\nRFA: \n"); + for ( pRfd = uti596_softc.pBeginRFA; + pRfd != I596_NULL; + pRfd = pRfd->next) + printf("Frame @ %p, status: %2.2x, cmd: %2.2x\n", + pRfd, pRfd->stat, pRfd->cmd); + + printf("\nInbound: \n"); + for ( pRfd = uti596_softc.pInboundFrameQueue; + pRfd != I596_NULL; + pRfd = pRfd->next) + printf("Frame @ %p, status: %2.2x, cmd: %2.2x\n", + pRfd, pRfd->stat, pRfd->cmd); + + + printf("\nSaved: \n"); + for ( pRfd = uti596_softc.pSavedRfdQueue; + pRfd != I596_NULL; + pRfd = pRfd->next) + printf("Frame @ %p, status: %2.2x, cmd: %2.2x\n", + pRfd, pRfd->stat, pRfd->cmd); + printf("\nUnknown: %p\n",uti596_softc.pLastUnkRFD); + +} +void show_queues(void) +{ + struct i596_rfd *pRfd; + + + printf("CMD: 0x%x, Status: 0x%x\n", + uti596_softc.scb.command, + uti596_softc.scb.status); + printf("saved Q\n"); + + for ( pRfd = uti596_softc.pSavedRfdQueue; + pRfd != I596_NULL && + pRfd != NULL; + pRfd = pRfd->next) + printf("0x%p\n", pRfd); + + printf("End saved Q 0x%p\n", uti596_softc.pEndSavedQueue); + + printf("\nRFA:\n"); + for ( pRfd = uti596_softc.pBeginRFA; + pRfd != I596_NULL && + pRfd != NULL; + pRfd = pRfd->next) + printf("0x%p\n", pRfd); + + printf("uti596_softc.pEndRFA: %p\n",uti596_softc.pEndRFA); +} + + +void uti596_init(void * arg){ + + struct uti596_softc *sc = arg; + struct ifnet *ifp = &sc->arpcom.ac_if; + + if (sc->txDaemonTid == 0) { + + uti596_initialize_hardware(sc); + + /* + * Start driver tasks + */ + + sc->txDaemonTid = rtems_bsdnet_newproc ("UTtx", 4096, uti596_txDaemon, sc); + sc->rxDaemonTid = rtems_bsdnet_newproc ("UTrx", 4096, uti596_rxDaemon, sc); + + } + /* + * Enable receiver + */ + sc->scb.pRfd = sc -> pBeginRFA; + sc->scb.command = RX_START; + outport_word(CHAN_ATTN,0 ); + UTI_WAIT_COMMAND_ACCEPTED(4000, "init:RX_START"); + /* + * Tell the world that we're running. + */ + ifp->if_flags |= IFF_RUNNING; + +} +void dump_scb(){ + printk("status 0x%x\n",uti596_softc.scb.status); + printk("command 0x%x\n",uti596_softc.scb.command); + printk("cmd 0x%x\n",(int)uti596_softc.scb.pCmd); + printk("rfd 0x%x\n",(int)uti596_softc.scb.pRfd); + printk("crc_err 0x%x\n",uti596_softc.scb.crc_err); + printk("align_err 0x%x\n",uti596_softc.scb.align_err); + printk("resource_err 0x%x\n",uti596_softc.scb.resource_err ); + printk("over_err 0x%x\n",uti596_softc.scb.over_err); + printk("rcvdt_err 0x%x\n",uti596_softc.scb.rcvdt_err); + printk("short_err 0x%x\n",uti596_softc.scb.short_err); + printk("t_on 0x%x\n",uti596_softc.scb.t_on); + printk("t_off 0x%x\n",uti596_softc.scb.t_off); +} + diff --git a/c/src/lib/libbsp/i386/i386ex/network/uti596.h b/c/src/lib/libbsp/i386/i386ex/network/uti596.h new file mode 100644 index 0000000000..0471ccdc4d --- /dev/null +++ b/c/src/lib/libbsp/i386/i386ex/network/uti596.h @@ -0,0 +1,276 @@ + +/* uti596.h: Contains the defines and structures used by the uti596 driver */ + +/* + * EII: March 11: Created v. 0.0 + * Jan 12/98 Added STAT bits, s11-=s5 and max_colls. + */ + +#ifndef UTI596_H +#define UTI596_H +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +/* Ethernet statistics */ + +struct enet_statistics{ + int rx_packets; /* total packets received */ + int tx_packets; /* total packets transmitted */ + int rx_errors; /* bad packets received */ + int tx_errors; /* packet transmit problems */ + int rx_dropped; /* no space in buffers */ + int tx_dropped; /* */ + int tx_retries_exceeded; /* excessive retries */ + int multicast; /* multicast packets received */ + int collisions; + + /* detailed rx_errors: */ + int rx_length_errors; + int rx_over_errors; /* receiver ring buff overflow */ + int rx_crc_errors; /* recved pkt with crc error */ + int rx_frame_errors; /* recv'd frame alignment error */ + int rx_fifo_errors; /* recv'r fifo overrun */ + int rx_missed_errors; /* receiver missed packet */ + + /* detailed tx_errors */ + int tx_aborted_errors; + int tx_carrier_errors; + int tx_fifo_errors; + int tx_heartbeat_errors; + int tx_window_errors; +}; + + + +enum commands { + CmdNOp = 0, + CmdSASetup = 1, + CmdConfigure = 2, + CmdMulticastList = 3, + CmdTx = 4, + CmdTDR = 5, + CmdDump = 6, + CmdDiagnose = 7 +}; + + +#define UTI596_MUTEX 1 + + +#define CMD_EOL 0x8000 /* The last command of the list, stop. */ +#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */ +#define CMD_INTR 0x2000 /* Interrupt after doing cmd. */ + +#define CMD_FLEX 0x0008 /* Enable flexible memory model */ + +#define SCB_STAT_CX 0x8000 /* Cmd completes with 'I' bit set */ +#define SCB_STAT_FR 0x4000 /* Frame Received */ +#define SCB_STAT_CNA 0x2000 /* Cmd unit Not Active */ +#define SCB_STAT_RNR 0x1000 /* Receiver Not Ready */ + +#define STAT_C 0x8000 /* Set to 1 after execution */ +#define STAT_B 0x4000 /* 1 : Cmd being executed, 0 : Cmd done. */ +#define STAT_OK 0x2000 /* 1: Command executed ok 0 : Error */ +#define STAT_A 0x1000 /* command has been aborted */ + +#define STAT_S11 0x0800 +#define STAT_S10 0x0400 +#define STAT_S9 0x0200 +#define STAT_S8 0x0100 +#define STAT_S7 0x0080 +#define STAT_S6 0x0040 +#define STAT_S5 0x0020 +#define STAT_MAX_COLLS 0x000F + + +#define RBD_STAT_P 0x4000 /* prefetch */ +#define RBD_STAT_F 0x4000 /* used */ + +#define CUC_START 0x0100 +#define CUC_RESUME 0x0200 +#define CUC_SUSPEND 0x0300 +#define CUC_ABORT 0x0400 +#define RX_START 0x0010 +#define RX_RESUME 0x0020 +#define RX_SUSPEND 0x0030 +#define RX_ABORT 0x0040 + +#define RU_SUSPENDED 0x001 +#define RU_NO_RESOURCES 0x0020 +#define RU_READY 0x0040 + + + +#define IO_ADDR 0x360 +#define PORT_ADDR IO_ADDR +#define CHAN_ATTN PORT_ADDR + 4 +#define NIC_ADDR PORT_ADDR + 8 + +struct i596_cmd { + volatile unsigned short status; + volatile unsigned short command; + struct i596_cmd *next; +}; + +#define I596_NULL ( ( void * ) 0xffffffff) +#define UTI_596_END_OF_FRAME 0x8000 +#define SIZE_MASK 0x3fff + +/* + * Transmit buffer Descriptor + */ + +struct i596_tbd { + unsigned short size; + unsigned short pad; + struct i596_tbd *next; + char *data; +}; + +/* + * Receive buffer Descriptor + */ + +struct i596_rbd { + unsigned short count; + unsigned short offset; + struct i596_rbd *next; + char *data; + unsigned short size; + unsigned short pad; +}; + +/* + * Transmit Command Structure + */ +struct tx_cmd { + struct i596_cmd cmd; + struct i596_tbd *pTbd; + unsigned short size; + unsigned short pad; +} ; + + +/* + * Receive Frame Descriptor + */ +struct i596_rfd { + volatile unsigned short stat; + volatile unsigned short cmd; + struct i596_rfd *next; + struct i596_rbd *pRbd; + unsigned short count; + unsigned short size; + char data [1532 ]; +} ; + + +struct i596_dump { + struct i596_cmd cmd; + char * pData; +}; + +struct i596_set_add { + struct i596_cmd cmd; + char data[8]; +}; + +struct i596_configure { + struct i596_cmd cmd; + char data[16]; +}; + + + +#define RX_RING_SIZE 8 + +/* + * System Control Block + */ +struct i596_scb { + volatile unsigned short status; + volatile unsigned short command; + struct i596_cmd *pCmd; + struct i596_rfd *pRfd; + volatile unsigned long crc_err; + volatile unsigned long align_err; + volatile unsigned long resource_err; + volatile unsigned long over_err; + volatile unsigned long rcvdt_err; + volatile unsigned long short_err; + volatile unsigned short t_on; + volatile unsigned short t_off; +}; + + +/* + * Intermediate System Control Block + */ +struct i596_iscp { + volatile unsigned long stat; + struct i596_scb *scb; +} ; +/* + * System Control Parameters + */ +struct i596_scp { + unsigned long sysbus; + unsigned long pad; + struct i596_iscp *iscp; +} ; + +struct uti596_softc { + struct arpcom arpcom; + rtems_irq_connect_data irqInfo; + struct i596_scp *pScp; + struct i596_iscp iscp; + struct i596_scb scb; + struct i596_set_add set_add; + struct i596_configure set_conf; + struct i596_cmd tdr; + unsigned long stat; + struct tx_cmd *pTxCmd; + struct i596_tbd *pTbd; + + int ioAddr; + + struct i596_rfd *pBeginRFA; + struct i596_rfd *pEndRFA; + struct i596_rfd *pLastUnkRFD; + struct i596_rbd *pLastUnkRBD; + struct i596_rfd *pEndSavedQueue; + struct i596_cmd *pCmdHead; + struct i596_cmd *pCmdTail; /* unneeded, as chaining not used, but implemented */ + + rtems_id rxDaemonTid; + rtems_id txDaemonTid; + + struct enet_statistics stats; + int started; + unsigned long rxInterrupts; + unsigned long txInterrupts; + volatile int cmdOk; + int resetDone; + unsigned long txRawWait; + struct i596_rfd *pInboundFrameQueue; + short int rxBdCount; + short int txBdCount; + short int countRFD; + short int savedCount; + struct i596_rfd *pSavedRfdQueue; + rtems_name semaphore_name; + rtems_id semaphore_id; + char zeroes[64]; + unsigned long rawsndcnt; +} ; +#endif -- cgit v1.2.3