📄 network.c
字号:
/* network.c: An 82596 ethernet driver for rtems-bsd. * * $Id: network.c,v 1.7 2002/11/01 21:50:47 joel Exp $ */#define KERNEL/* * Selectively define to debug the network driver. If you define any of these * you must run with polled console I/O. */ /* #define DBG_ADD_CMD#define DBG_WAIT#define DBG_SEND#define DBG_MEM#define DBG_SELFTEST_CMD#define DBG_DUMP_CMD#define DBG_RESET#define DBG_ATTACH#define DBG_START#define DBG_INIT#define DBG_STOP#define DBG_RX#define DBG_ISR#define DBG_IOCTL#define DBG_STAT#define DBG_PACKETS*//* * Default number of buffer descriptors and buffer sizes. */#define RX_BUF_COUNT 15#define TX_BUF_COUNT 4#define TX_BD_PER_BUF 4#define RBUF_SIZE 1520#define UTI_596_ETH_MIN_SIZE 60#define INET_ADDR_MAX_BUF_SIZE (sizeof "255.255.255.255")/* * RTEMS events */#define INTERRUPT_EVENT RTEMS_EVENT_1#define START_TRANSMIT_EVENT RTEMS_EVENT_2#define NIC_RESET_EVENT RTEMS_EVENT_3#include <bsp.h>#include <stdio.h>#include <string.h>#include <stdlib.h>#include <rtems/error.h>#include <rtems/rtems_bsdnet.h>#include <sys/param.h>#include <sys/mbuf.h>#include <sys/socket.h>#include <sys/sockio.h>#include <sys/types.h>#include <net/if.h>#include <netinet/in.h>#include <netinet/if_ether.h>#include <arpa/inet.h>#include "uti596.h"/* If we are running interrupt driven I/O no debug output is printed */#if CD2401_POLLED_IO == 1 #define printk(arglist) printk arglist;#else #define printk(arglist)#endif#define UTI_596_ASSERT( condition, str ) if (!( condition ) ) { printk((str)) }/* Types of PORT commands */#define UTI596_RESET_PORT_FUNCTION 0#define UTI596_SELFTEST_PORT_FUNCTION 1#define UTI596_SCP_PORT_FUNCTION 2#define UTI596_DUMP_PORT_FUNCTION 3/* Types of waiting for commands */#define UTI596_NO_WAIT 0#define UTI596_WAIT_FOR_CU_ACCEPT 1#define UTI596_WAIT_FOR_INITIALIZATION 2#define UTI596_WAIT_FOR_STAT_C 3/* Device dependent data structure */static uti596_softc_ uti596_softc;/* Globals */int count_rx = 0;static int scbStatus;static rtems_status_code sc;static i596_cmd *pIsrCmd;static i596_rfd *pIsrRfd;/* * Initial 596 configuration */char uti596initSetup[] = { 0x0E, /* Byte 0: length, prefetch off ( no RBD's ) */ 0xC8, /* Byte 1: fifo to 8, monitor off */ 0x40, /* Byte 2: don't save bad frames ( was save= 80, use intel's 40 )*/ 0x2E, /* Byte 3: No source address insertion, 8 byte preamble */ 0x00, /* Byte 4: priority and backoff defaults */ 0x60, /* Byte 5: interframe spacing */ 0x00, /* Byte 6: slot time LSB */ 0xf2, /* Byte 7: slot time and retries */ 0x0C, /* Byte 8: not promisc, enable bcast, tx no crs, crc inserted 32bit, 802.3 framing */ 0x08, /* Byte 9: collision detect */ 0x40, /* Byte 10: minimum frame length */ 0xfb, /* Byte 11: tried C8 same as byte 1 in bits 6-7, else ignored*/ 0x00, /* Byte 12: disable full duplex */ 0x3f /* Byte 13: no multi IA, backoff enabled */};/* Local Routines */static unsigned long word_swap ( unsigned long );static void * malloc_16byte_aligned ( void **, void ** adjusted_pointer, size_t );RTEMS_INLINE_ROUTINE void uti596_writePortFunction ( volatile void *, unsigned long );RTEMS_INLINE_ROUTINE void uti596_portReset( void );static unsigned long uti596_portSelfTest( i596_selftest * );static int uti596_portDump ( i596_dump_result * );static int uti596_wait ( uti596_softc_ *, unsigned8 );static int uti596_issueCA ( uti596_softc_ *, unsigned8 );static void uti596_addCmd ( i596_cmd * );static void uti596_addPolledCmd ( i596_cmd * );static void uti596_CU_dump ( i596_dump_result * );static void uti596_dump_scb ( void );static int uti596_setScpAndScb ( uti596_softc_ * );static int uti596_diagnose ( void );static int uti596_configure ( uti596_softc_ * );static int uti596_IAsetup ( uti596_softc_ * );static int uti596_initTBD ( uti596_softc_ * );static int uti596_initRFA ( int );static void uti596_initMem ( uti596_softc_ * );static void uti596_initialize ( uti596_softc_ * );static void uti596_initialize_hardware ( uti596_softc_ * );static void uti596_reset_hardware ( uti596_softc_ *);static void uti596_reset ( void );static void uti596_clearListStatus ( i596_rfd * );static i596_rfd * uti596_dequeue ( i596_rfd ** );static void uti596_append ( i596_rfd ** , i596_rfd * );static void uti596_supplyFD ( i596_rfd * );static void send_packet ( struct ifnet *, struct mbuf * );/* Required RTEMS network driver functions and tasks (plus reset daemon) */static void uti596_start ( struct ifnet * );void uti596_init ( void * );void uti596_stop ( uti596_softc_ * );void uti596_txDaemon ( void * );void uti596_rxDaemon ( void * );void uti596_resetDaemon( void * );rtems_isr uti596_DynamicInterruptHandler ( rtems_vector_number );static int uti596_ioctl ( struct ifnet *, int, caddr_t );void uti596_stats ( uti596_softc_ * );#ifdef DBG_PACKETSstatic void dumpQ( void );static void show_buffers( void );static void show_queues( void );static void print_eth ( unsigned char * );static void print_hdr ( unsigned char * );static void print_pkt ( unsigned char * );static void print_echo ( unsigned char * );#endif/* * word_swap * * Return a 32 bit value, swapping the upper and lower words first. * * Input parameters: * val - 32 bit value to swap * * Output parameters: NONE * * Return value: * Input value with upper and lower 16-bit words swapped */static unsigned long word_swap( unsigned long val){ return (((val >> 16)&(0x0000ffff)) | ((val << 16)&(0xffff0000)));}/* * malloc_16byte_aligned * * Allocate a block of a least nbytes aligned on a 16-byte boundary. * Clients are responsible to store both the real address and the adjusted * address. The real address must be used to free the block. * * Input parameters: * real_pointer - pointer to a void * pointer in which to store the starting * address of the block. Required for free. * adjusted_pointer - pointer to a void * pointer in which to store the * starting address of the block rounded up to the next * 16 byte boundary. * nbytes - number of bytes of storage requested * * Output parameters: * real_pointer - starting address of the block. * adjusted_pointer - starting address of the block rounded up to the next * 16 byte boundary. * * Return value: * starting address of the block rounded up to the next 16 byte boundary. * NULL if no storage was allocated. */static void * malloc_16byte_aligned( void ** real_pointer, void ** adjusted_pointer, size_t nbytes){ *real_pointer = malloc( nbytes + 0xF, 0, M_NOWAIT ); *adjusted_pointer = (void *)(((unsigned long)*real_pointer + 0xF ) & 0xFFFFFFF0 ); return *adjusted_pointer;}/* * uti596_scp_alloc * * Allocate a new scp, possibly freeing a previously allocated one. * * Input parameters: * sc - pointer to the global uti596_softc in which to store pointers * to the newly allocated block. * * Output parameters: NONE * * Return value: * Pointer to the newly allocated, 16-byte aligned scp. */static i596_scp * uti596_scp_alloc( uti596_softc_ * sc){ if( sc->base_scp != NULL ) { #ifdef DBG_MEM printk(("uti596_scp_alloc: Already have an SCP at %p\n", sc->base_scp)) #endif return sc->pScp; } /* allocate enough memory for the Scp block to be aligned on 16 byte boundary */ malloc_16byte_aligned( (void *)&(sc->base_scp), (void *)&(sc->pScp), sizeof( i596_scp ) ); #ifdef DBG_MEM printk(("uti596_scp_alloc: Scp base address is %p\n", sc->base_scp)) printk(("uti596_scp_alloc: Scp aligned address is : %p\n",sc->pScp)) #endif return sc->pScp;}/* * uti596_writePortFunction * * Write the command into the PORT. * * Input parameters: * addr - 16-byte aligned address to write into the PORT. * cmd - 4-bit cmd to write into the PORT * * Output parameters: NONE * * Return value: NONE * * The Motorola manual swapped the high and low registers. */RTEMS_INLINE_ROUTINE void uti596_writePortFunction( volatile void * addr, unsigned long cmd){ i82596->port_lower = (unsigned short)(((unsigned long)addr & 0xFFF0) | cmd); i82596->port_upper = (unsigned short)(((unsigned long)addr >> 16 ) & 0xFFFF);}/* * uti596_portReset * * Issue a port Reset to the uti596 * * Input parameters: NONE * * Output parameters: NONE * * Return value: NONE */RTEMS_INLINE_ROUTINE void uti596_portReset( void ){ uti596_writePortFunction( NULL, UTI596_RESET_PORT_FUNCTION );}/* * uti596_portSelfTest * * Perform a self-test. Wait for up to 1 second for the test to * complete. Normally, the test should complete in a very short time, * so busy waiting is not an issue. * * Input parameters: * stp - pointer to a 16-byte aligned uti596_selftest structure. * * Output parameters: NONE * * Return value: * 32-bit result field if successful, -1 otherwise. */static unsigned long uti596_portSelfTest( i596_selftest * stp){ rtems_interval ticks_per_second, start_ticks, end_ticks; stp->results = 0xFFFFFFFF; uti596_writePortFunction( stp, UTI596_SELFTEST_PORT_FUNCTION ); rtems_clock_get(RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticks_per_second); rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks); end_ticks = start_ticks + ticks_per_second; do { if( stp->results != 0xFFFFFFFF ) break; else rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks); } while (start_ticks <= end_ticks); if (start_ticks > end_ticks ) { #ifdef DBG_SELFTEST_CMD printk(("uti596_selftest: Timed out\n" )) #endif return -1; } else { #ifdef DBG_SELFTEST_CMD printk(("uti596_selftest: Succeeded with signature = 0x%08x, result = 0x%08x\n", stp->signature, stp->results)) #endif return stp->results; }} /* * uti596_portDump * * Perform a dump Wait for up to 1 second for the test to * complete. Normally, the test should complete in a very short time, * so busy waiting is not an issue. * * Input parameters: * dp - pointer to a 16-byte aligned uti596_dump structure. * * Output parameters: NONE * * Return value: * 16-bit dump_status field if successful, -1 otherwise. */static int uti596_portDump( i596_dump_result * dp){ rtems_interval ticks_per_second, start_ticks, end_ticks; dp->dump_status = 0; uti596_writePortFunction( dp, UTI596_DUMP_PORT_FUNCTION ); rtems_clock_get(RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticks_per_second); rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks); end_ticks = start_ticks + ticks_per_second; do { if( dp->dump_status != 0xA006 ) break; else rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks); } while (start_ticks <= end_ticks); if (start_ticks > end_ticks ) { #ifdef DBG_DUMP_CMD printk(("uti596_dump: Timed out with dump at 0x%08x\n", (unsigned long)dp )) #endif return -1; } else { #ifdef DBG_DUMP_CMD printk(("uti596_dump: Succeeded with dump at = 0x%08x\n", (unsigned long)dp )) #endif return dp->dump_status; }}/* * uti596_wait * * Wait for a certain condition. * * Input parameters: * sc - pointer to the uti596_softc struct * wait_type - UTI596_NO_WAIT * UTI596_WAIT * UTI596_WAIT_FOR_CU_ACCEPT * UTI596_WAIT_FOR_INITIALIZATION * UTI596_WAIT_FOR_STAT_C * * Output parameters: NONE * * Return value: * 0 if successful, -1 otherwise. */static int uti596_wait( uti596_softc_ *sc, unsigned8 waitType){ rtems_interval ticks_per_second, start_ticks, end_ticks; rtems_clock_get(RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticks_per_second); rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks); end_ticks = start_ticks + ticks_per_second; switch( waitType ) { case UTI596_NO_WAIT: return 0; case UTI596_WAIT_FOR_CU_ACCEPT: do { if (sc->scb.command == 0) break; else rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks); } while (start_ticks <= end_ticks); if( (sc->scb.command != 0) || (start_ticks > end_ticks) ) { printf("i82596 timed out with status %x, cmd %x.\n", sc->scb.status, sc->scb.command); return -1; } else return 0; case UTI596_WAIT_FOR_INITIALIZATION: do { if( !sc->iscp.busy ) break; else rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &start_ticks); } while (start_ticks <= end_ticks); if (start_ticks > end_ticks ) { #ifdef DBG_WAIT printk(("uti596_setScpAndScb: Timed out\n" )) #endif return -1; } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -