📄 sonic.c
字号:
/* * RTEMS NETWORK DRIVER FOR NATIONAL DP83932 `SONIC' * SYSTEMS-ORIENTED NETWORK INTERFACE CONTROLLER * * REUSABLE CHIP DRIVER * * References: * * 1) DP83932C-20/25/33 MHz SONIC(TM) Systems-Oriented Network Interface * Controller data sheet. TL/F/10492, RRD-B30M105, National Semiconductor, * 1995. * * 2) Software Driver Programmer's Guide for the DP83932 SONIC(TM), * Application Note 746, Wesley Lee and Mike Lui, TL/F/11140, * RRD-B30M75, National Semiconductor, March, 1991. * * COPYRIGHT (c) 1989-1997. * On-Line Applications Research Corporation (OAR). * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * http://www.rtems.com/license/LICENSE. * * $Id: sonic.c,v 1.7.4.1 2003/09/04 18:46:04 joel Exp $ * * This driver was originally written and tested on a DY-4 DMV177, * which had a 100 Mhz PPC603e. * * This driver also works with DP83934CVUL-20/25 MHz, tested on * Tharsys ERC32 VME board. * * Rehaul to fix lost interrupts and buffers, and to use to use * interrupt-free transmission by Jiri, 22/03/1999. */#include <rtems.h>#include <rtems/rtems_bsdnet.h>#include <libchip/sonic.h>#include <stdio.h>#include <string.h>#include <errno.h>#include <rtems/error.h>#include <sys/param.h>#include <sys/mbuf.h>#include <sys/socket.h>#include <sys/sockio.h>#include <sys/sockio.h>#include <net/if.h>#include <netinet/in.h>#include <netinet/if_ether.h>/* * XXX fix this */void *set_vector(void *, unsigned32, unsigned32);#if (SONIC_DEBUG & SONIC_DEBUG_DUMP_MBUFS)#include <rtems/dumpbuf.h>#endif/* * Use the top line if you want more symbols. */#define SONIC_STATIC /* #define SONIC_STATIC static *//* * Number of devices supported by this driver */#ifndef NSONIC# define NSONIC 1#endif/* * * As suggested by National Application Note 746, make the * receive resource area bigger than the receive descriptor area. * * NOTE: Changing this may break this driver since it currently * assumes a 1<->1 mapping. */#define RRA_EXTRA_COUNT 0/* * RTEMS event used by interrupt handler to signal daemons. */#define INTERRUPT_EVENT RTEMS_EVENT_1/* * RTEMS event used to start transmit daemon. * This must not be the same as INTERRUPT_EVENT. */#define START_TRANSMIT_EVENT RTEMS_EVENT_2/* * Largest Ethernet frame. */#define MAXIMUM_FRAME_SIZE 1518/* * Receive buffer size. * Allow for a pointer, plus a full ethernet frame (including Frame * Check Sequence) rounded up to a 4-byte boundary. */#define RBUF_SIZE ((sizeof (void *) + (MAXIMUM_FRAME_SIZE) + 3) & ~3)/* #define RBUF_WC ((((MAXIMUM_FRAME_SIZE) + 3) & ~3) / 2) */#define RBUF_WC (RBUF_SIZE / 2)/* * Macros for manipulating 32-bit pointers as 16-bit fragments */#define LSW(p) ((rtems_unsigned16)((rtems_unsigned32)(p)))#define MSW(p) ((rtems_unsigned16)((rtems_unsigned32)(p) >> 16))#define PTR(m,l) ((void*)(((rtems_unsigned16)(m)<<16)|(rtems_unsigned16)(l)))/* * Hardware-specific storage */struct sonic_softc { /* * Connection to networking code * This entry *must* be the first in the sonic_softc structure. */ struct arpcom arpcom; /* * Default location of device registers * ===CACHE=== * This area must be non-cacheable, guarded. */ void *sonic; /* * Register access routines */ sonic_write_register_t write_register; sonic_read_register_t read_register; /* * Interrupt vector */ rtems_vector_number vector; /* * Data Configuration Register values */ rtems_unsigned32 dcr_value; rtems_unsigned32 dc2_value; /* * Indicates configuration */ int acceptBroadcast; /* * Task waiting for interrupts */ rtems_id rxDaemonTid; rtems_id txDaemonTid; /* * Receive resource area */ int rdaCount; ReceiveResourcePointer_t rsa; ReceiveResourcePointer_t rea; CamDescriptorPointer_t cdp; ReceiveDescriptorPointer_t rda; ReceiveDescriptorPointer_t rdp_last; /* * Transmit descriptors */ int tdaCount; TransmitDescriptorPointer_t tdaHead; /* Last filled */ TransmitDescriptorPointer_t tdaTail; /* Next to retire */ /* * Statistics */ unsigned long Interrupts; unsigned long rxInterrupts; unsigned long rxMissed; unsigned long rxGiant; unsigned long rxNonOctet; unsigned long rxBadCRC; unsigned long rxCollision; unsigned long txInterrupts; unsigned long txSingleCollision; unsigned long txMultipleCollision; unsigned long txCollision; unsigned long txDeferred; unsigned long txUnderrun; unsigned long txLateCollision; unsigned long txExcessiveCollision; unsigned long txExcessiveDeferral; unsigned long txLostCarrier; unsigned long txRawWait;};SONIC_STATIC struct sonic_softc sonic_softc[NSONIC];/* ****************************************************************** * * * Debug Routines * * * ****************************************************************** */#if (SONIC_DEBUG & SONIC_DEBUG_MEMORY_DESCRIPTORS)void sonic_print_tx_descriptor( TransmitDescriptorPointer_t tdp){ printf( "TXD ==> %p", tdp ); printf( " pkt_config = 0x%04x", tdp->pkt_config & 0xffff); printf( " pkt_size = 0x%04x\n", tdp->pkt_size & 0xffff ); printf( " frag_count = %d", tdp->frag_count & 0xffff ); /* could print all the fragments */ printf( " next = %p", tdp->next ); printf( " linkp = %p\n", tdp->linkp ); printf( " mbufp = %p", tdp->mbufp ); if ( tdp->mbufp ) printf( " mbufp->data = %p", mtod ( tdp->mbufp, void *) ); puts("");}void sonic_print_rx_descriptor( ReceiveDescriptorPointer_t rdp){ printf( "RXD ==> %p\n", rdp ); printf( " status = 0x%04x", rdp->status & 0xffff ); printf( " byte_count = 0x%04x\n", rdp->byte_count & 0xffff ); printf( " pkt = 0x%04x%04x", rdp->pkt_msw, rdp->pkt_lsw ); printf( " seq_no = %d", rdp->seq_no ); printf( " link = %d\n", rdp->link ); printf( " in_use = %d", rdp->in_use ); printf( " next = %p", rdp->next ); printf( " mbufp = %p", rdp->mbufp ); if ( rdp->mbufp ) printf( " mbufp->data = %p", mtod ( rdp->mbufp, void *) ); puts("");}#endif/* ****************************************************************** * * * Support Routines * * * ****************************************************************** */void sonic_enable_interrupts( struct sonic_softc *sc, unsigned32 mask){ void *rp = sc->sonic; rtems_interrupt_level level; rtems_interrupt_disable( level ); (*sc->write_register)( rp, SONIC_REG_IMR, (*sc->read_register)(rp, SONIC_REG_IMR) | mask ); rtems_interrupt_enable( level );}void sonic_disable_interrupts( struct sonic_softc *sc, unsigned32 mask){ void *rp = sc->sonic; rtems_interrupt_level level; rtems_interrupt_disable( level ); (*sc->write_register)( rp, SONIC_REG_IMR, (*sc->read_register)(rp, SONIC_REG_IMR) & ~mask ); rtems_interrupt_enable( level );}void sonic_clear_interrupts( struct sonic_softc *sc, unsigned32 mask){ void *rp = sc->sonic; rtems_interrupt_level level; rtems_interrupt_disable( level ); (*sc->write_register)( rp, SONIC_REG_ISR, mask); rtems_interrupt_enable( level );}void sonic_command( struct sonic_softc *sc, unsigned32 mask){ void *rp = sc->sonic; rtems_interrupt_level level; rtems_interrupt_disable( level ); (*sc->write_register)( rp, SONIC_REG_CR, mask); rtems_interrupt_enable( level );}/* * Allocate non-cacheable memory on a single 64k page. * Very simple minded -- just keeps trying till the memory is on a single page. */SONIC_STATIC void * sonic_allocate(unsigned int nbytes){ void *p; unsigned long a1, a2; for (;;) { /* * ===CACHE=== * Change malloc to malloc_noncacheable_guarded. */ p = malloc( nbytes, M_MBUF, M_NOWAIT ); if (p == NULL) rtems_panic ("No memory!"); memset (p, '\0', nbytes); a1 = (unsigned long)p; a2 = a1 + nbytes - 1; if ((a1 >> 16) == (a2 >> 16)) break; }#if (SONIC_DEBUG & SONIC_DEBUG_MEMORY_ALLOCATE) printf( "sonic_allocate %d bytes at %p\n", nbytes, p );#endif return p;}/* * Shut down the interface. */SONIC_STATIC void sonic_stop (struct sonic_softc *sc){ struct ifnet *ifp = &sc->arpcom.ac_if; ifp->if_flags &= ~IFF_RUNNING; /* * Stop the transmitter and receiver. */ sonic_command(sc, CR_HTX | CR_RXDIS );}/* * Show interface statistics */SONIC_STATIC void sonic_stats (struct sonic_softc *sc){ printf (" Total Interrupts:%-8lu", sc->Interrupts); printf (" Rx Interrupts:%-8lu", sc->rxInterrupts); printf (" Giant:%-8lu", sc->rxGiant); printf (" Non-octet:%-8lu\n", sc->rxNonOctet); printf (" Bad CRC:%-8lu", sc->rxBadCRC); printf (" Collision:%-8lu", sc->rxCollision); printf (" Missed:%-8lu\n", sc->rxMissed); printf ( " Tx Interrupts:%-8lu", sc->txInterrupts); printf ( " Deferred:%-8lu", sc->txDeferred); printf (" Lost Carrier:%-8lu\n", sc->txLostCarrier); printf ( "Single Collisions:%-8lu", sc->txSingleCollision); printf ( "Multiple Collisions:%-8lu", sc->txMultipleCollision); printf ("Excessive Collisions:%-8lu\n", sc->txExcessiveCollision); printf ( " Total Collisions:%-8lu", sc->txCollision); printf ( " Late Collision:%-8lu", sc->txLateCollision); printf (" Underrun:%-8lu\n", sc->txUnderrun); printf ( " Raw output wait:%-8lu\n", sc->txRawWait);}/* ****************************************************************** * * * Interrupt Handler * * * ****************************************************************** */SONIC_STATIC rtems_isr sonic_interrupt_handler (rtems_vector_number v){ struct sonic_softc *sc = sonic_softc; unsigned32 isr, imr; void *rp;#if (NSONIC > 1) /* * Find the device which requires service */ for (;;) { if (sc->vector == v) break; if (++sc == &sonic[NSONIC]) return; /* Spurious interrupt? */ }#endif /* NSONIC > 1 */ /* * Get pointer to SONIC registers */ rp = sc->sonic; sc->Interrupts++; isr = (*sc->read_register)( rp, SONIC_REG_ISR ); imr = (*sc->read_register)( rp, SONIC_REG_IMR ); /* * Packet received or receive buffer area exceeded? */ if (imr & isr & (IMR_PRXEN | IMR_RBAEEN)) { imr &= ~(IMR_PRXEN | IMR_RBAEEN); sc->rxInterrupts++; rtems_event_send (sc->rxDaemonTid, INTERRUPT_EVENT); (*sc->write_register)( rp, SONIC_REG_IMR, imr ); (*sc->write_register)( rp, SONIC_REG_ISR, isr & ISR_PKTRX ); } /* * Packet started, transmitter done or transmitter error? * TX interrupts only occur after an error or when all TDA's are * exhausted and we are waiting for buffer to come free. */ if (imr & isr & (IMR_PINTEN | IMR_TXEREN)) { sc->txInterrupts++; rtems_event_send (sc->txDaemonTid, INTERRUPT_EVENT); (*sc->write_register)( rp, SONIC_REG_ISR, ISR_PINT | ISR_TXDN | ISR_TXER ); }}/* ****************************************************************** * * * Transmitter Routines * * * ****************************************************************** *//* * Soak up transmit descriptors that have been sent. */SONIC_STATIC void sonic_retire_tda (struct sonic_softc *sc){ rtems_unsigned16 status; unsigned int collisions; struct mbuf *m, *n; /* * Repeat for all completed transmit descriptors. */ while ((status = sc->tdaTail->status) != 0) {#if (SONIC_DEBUG & SONIC_DEBUG_DESCRIPTORS) printf( "retire TDA %p (0x%04x)\n", sc->tdaTail, status );#endif#if (SONIC_DEBUG & SONIC_DEBUG_ERRORS) /* * If there is an error that was not a collision, * then someone may want to see it. */ if ( (status & ~(TDA_STATUS_COLLISION_MASK|TDA_STATUS_DEF)) != 0x0001 ) printf( "ERROR: retire TDA %p (0x%08x)\n", sc->tdaTail, sc->tdaTail->status );#endif /* * Check for errors which stop the transmitter. */ if (status & (TDA_STATUS_EXD | TDA_STATUS_EXC | TDA_STATUS_FU | TDA_STATUS_BCM)) { /* * Restart the transmitter if there are * packets waiting to go. */ rtems_unsigned16 link;#if (SONIC_DEBUG & SONIC_DEBUG_ERRORS) printf("restarting sonic after error\n");#endif link = *(sc->tdaTail->linkp); if ((link & TDA_LINK_EOL) == 0) { void *rp = sc->sonic; (*sc->write_register)( rp, SONIC_REG_CTDA, link ); sonic_command(sc, CR_TXP ); } } /* * Update network statistics */ collisions = (status & TDA_STATUS_COLLISION_MASK) >> TDA_STATUS_COLLISION_SHIFT; if (collisions) { if (collisions == 1) sc->txSingleCollision++; else sc->txMultipleCollision++; sc->txCollision += collisions; } if (status & TDA_STATUS_EXC) sc->txExcessiveCollision++; if (status & TDA_STATUS_OWC) sc->txLateCollision++; if (status & TDA_STATUS_EXD) sc->txExcessiveDeferral++; if (status & TDA_STATUS_DEF) sc->txDeferred++; if (status & TDA_STATUS_FU) sc->txUnderrun++; if (status & TDA_STATUS_CRSL) sc->txLostCarrier++; /* * Free the packet and reset a couple of fields */ m = sc->tdaTail->mbufp; while ( m ) { MFREE(m, n); m = n; } /* sc->tdaTail->frag[0].frag_link = LSW(sc->tdaTail->link_pad); sc->tdaTail->frag_count = 0; */ sc->tdaTail->status = 0; /* * Move to the next transmit descriptor */ sc->tdaTail = sc->tdaTail->next;#if (SONIC_DEBUG & SONIC_DEBUG_DESCRIPTORS) printf( "next TDA %p\n", sc->tdaTail );#endif }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -