if_i82544.c
来自「eCos操作系统源码」· C语言 代码 · 共 2,128 行 · 第 1/5 页
C
2,128 行
//// TRANSMIT DESCRIPTORS//// ------------------------------------------------------------------------// Currently we only use the legacy Tx descriptor#define I82544_TD_BUFFER 0#define I82544_TD_LENGTH 8#define I82544_TD_CSO 10#define I82544_TD_CMD 11#define I82544_TD_STATUS 12#define I82544_TD_CSS 13#define I82544_TD_SPECIAL 14#define I82544_TD_SIZE 16#define I82544_TD_CMD_EOP (1<<0)#define I82544_TD_CMD_IFCS (1<<1)#define I82544_TD_CMD_IC (1<<2)#define I82544_TD_CMD_RS (1<<3)#define I82544_TD_CMD_RPS (1<<4)#define I82544_TD_CMD_DEXT (1<<5)#define I82544_TD_CMD_VLE (1<<6)#define I82544_TD_CMD_IDE (1<<7)#define I82544_TD_STATUS_DD (1<<0)#define I82544_TD_STATUS_EC (1<<1)#define I82544_TD_STATUS_LC (1<<2)#define I82544_TD_STATUS_TU (1<<3)// ------------------------------------------------------------------------//// DEVICES AND PACKET QUEUES//// ------------------------------------------------------------------------#define MAX_RX_PACKET_SIZE 1536 // maximum Rx packet size#define MAX_TX_PACKET_SIZE 1536 // maximum Tx packet size// ------------------------------------------------------------------------// Use arrays provided by platform header to verify pointers.#ifdef CYGDBG_USE_ASSERTS#define CHECK_NDP_SC_LINK() \ CYG_MACRO_START \ int i, valid_netdev = 0, valid_sc = 0; \ for(i = 0; i < CYGNUM_DEVS_ETH_INTEL_I82544_DEV_COUNT; i++) { \ if (i82544_netdev_array[i] == ndp) valid_netdev = 1; \ if (i82544_sc_array[i] == sc) valid_sc = 1; \ if (valid_sc || valid_netdev) break; \ } \ CYG_ASSERT( valid_netdev, "Bad ndp" ); \ CYG_ASSERT( valid_sc, "Bad sc" ); \ CYG_ASSERT( (void *)p_i82544 == i82544_sc_array[i]->driver_private, \ "sc pointer bad" ); \ CYG_MACRO_END#else#define CHECK_NDP_SC_LINK()#endif#define IF_BAD_82544( _p_ ) \if (({ \ int i, valid_p = 0; \ for(i = 0; i < CYGNUM_DEVS_ETH_INTEL_I82544_DEV_COUNT; i++) { \ if (i82544_priv_array[i] == (_p_)) { \ valid_p = 1; \ break; \ } \ } \ CYG_ASSERT(valid_p, "Bad pointer-to-i82544"); \ (!valid_p); \}))// ------------------------------------------------------------------------//// Managing the memory that is windowed onto the PCI bus//// ------------------------------------------------------------------------static cyg_uint32 i82544_heap_size;static cyg_uint8 *i82544_heap_base;static cyg_uint8 *i82544_heap_free;static void *mem_reserved_ioctl = (void*)0;// uncacheable memory reserved for ioctl calls// ------------------------------------------------------------------------//// FUNCTION PROTOTYPES//// ------------------------------------------------------------------------static int pci_init_find_82544s(void);static void i82544_reset(struct i82544* p_i82544);static void i82544_setup(struct i82544* p_i82544);static int eth_set_mac_address(struct i82544* p_i82544, cyg_uint8 *addr, int eeprom );static void InitRxRing(struct i82544* p_i82544);static void InitTxRing(struct i82544* p_i82544);static cyg_uint32eth_isr(cyg_vector_t vector, cyg_addrword_t data);static int i82544_configure(struct i82544* p_i82544, int promisc, int oversized);// debugging/logging only://void dump_txcb(TxCB* p_txcb);void DisplayStatistics(void);void update_statistics(struct i82544* p_i82544);//void dump_rfd(RFD* p_rfd, int anyway );void dump_all_rfds( int intf );void dump_packet(cyg_uint8 *p_buffer, int length);static void i82544_stop( struct eth_drv_sc *sc );// ------------------------------------------------------------------------static voidudelay(int delay){ CYGACC_CALL_IF_DELAY_US(delay);}// ------------------------------------------------------------------------// If we are demuxing for all interrupt sources, we must mask and unmask// *all* interrupt sources together.static inline int Mask82544Interrupt(struct i82544* p_i82544){ cyg_drv_interrupt_mask(p_i82544->vector); return 1;}static inline voidUnMask82544Interrupt(struct i82544* p_i82544, int old){ if (old & 1) cyg_drv_interrupt_unmask(p_i82544->vector);}static inline voidAcknowledge82544Interrupt(struct i82544* p_i82544){ cyg_drv_interrupt_acknowledge(p_i82544->vector);}// ------------------------------------------------------------------------// Memory management//// Simply carve off from the front of the PCI mapped window into real memorystatic CYG_ADDRESSpciwindow_mem_alloc(int size){ CYG_ADDRESS p_memory; int _size = size;#ifdef DEBUG// db_printf("pciwindow_mem_alloc %d\n",size);#endif CYG_ASSERT( (CYGHWR_INTEL_I82544_PCI_MEM_MAP_BASE <= (int)i82544_heap_free) && ((CYGHWR_INTEL_I82544_PCI_MEM_MAP_BASE + CYGHWR_INTEL_I82544_PCI_MEM_MAP_SIZE) > (int)i82544_heap_free) && (0 < i82544_heap_size) && (CYGHWR_INTEL_I82544_PCI_MEM_MAP_SIZE >= i82544_heap_size) && (CYGHWR_INTEL_I82544_PCI_MEM_MAP_BASE == (int)i82544_heap_base), "Heap variables corrupted" ); p_memory = 0; size = (size + 3) & ~3; if ( (i82544_heap_free+size) < (i82544_heap_base+i82544_heap_size) ) { cyg_uint32 *p; p_memory = (CYG_ADDRESS)i82544_heap_free; i82544_heap_free += size; for ( p = (cyg_uint32 *)p_memory; _size > 0; _size -= 4 ) *p++ = 0; } CYG_ASSERT( NULL == p_memory || VIRT_TO_BUS( p_memory ) + size == VIRT_TO_BUS( i82544_heap_free ), "Discontiguous PCI memory in real addresses" ); return p_memory;}// ------------------------------------------------------------------------//// MDIO//// Device-specific bit-twiddling and line driving side-effects// CYGACC_CALL_IF_DELAY_US() drags in huge amounts of scheduler locking and// the like 'cos it's a VV call! We only want a delay of 1uS tops, so:#define MII_DELAY() do { int z; for ( z = 0; z < 100; z++ ) ; } while (0)#if 0# define MII_PRINTF diag_printf# define MII_STUFF "%4s | %4s | %4s | %4s [%08x]\n", \ (*_ctrl & (1<<20)) ? "MDIO" : "---", \ (*_ctrl & (1<<24)) ? "Wr" : "Rd", \ (*_ctrl & (1<<21)) ? "CLK" : "clk", \ *_ctrl#else# define MII_PRINTF( foo )# define MII_STUFF#endifstatic inline cyg_uint32 mii_init( int ioaddr ){ cyg_uint32 ctrl; cyg_uint32 *_ctrl = &ctrl; *_ctrl = INL( ioaddr + I82544_CTRL ); *_ctrl &=~ I82544_CTRL_MDC; *_ctrl |= I82544_CTRL_MDC_DIR; *_ctrl &= ~I82544_CTRL_MDIO_DIR; *_ctrl &= ~I82544_CTRL_MDIO; OUTL( *_ctrl, ioaddr + I82544_CTRL ); MII_PRINTF( "mii_init : " MII_STUFF ); MII_DELAY(); return *_ctrl;}static inline void mii_clock_up( int ioaddr, cyg_uint32 *_ctrl ){ *_ctrl |= I82544_CTRL_MDC; OUTL( *_ctrl, ioaddr + I82544_CTRL ); MII_PRINTF( "mii_clock_up : " MII_STUFF ); MII_DELAY();}static inline void mii_clock_down( int ioaddr, cyg_uint32 *_ctrl ){ *_ctrl &=~ I82544_CTRL_MDC; OUTL( *_ctrl, ioaddr + I82544_CTRL ); MII_PRINTF( "mii_clock_down: " MII_STUFF ); MII_DELAY();}static inline void mii_read_mode( int ioaddr, cyg_uint32 *_ctrl ){ *_ctrl &= ~I82544_CTRL_MDIO_DIR; *_ctrl &= ~I82544_CTRL_MDIO; OUTL( *_ctrl, ioaddr + I82544_CTRL ); MII_PRINTF( "mii_read_mode : " MII_STUFF ); MII_DELAY();}static inline int mii_read_data_bit( int ioaddr, cyg_uint32 *_ctrl ){ *_ctrl = INL( ioaddr + I82544_CTRL ); MII_PRINTF( "mii_read_data : " MII_STUFF ); return I82544_CTRL_MDIO == (I82544_CTRL_MDIO & *_ctrl);}static inline void mii_write_data_bit( int ioaddr, int databit, cyg_uint32 *_ctrl ){ if ( databit ) *_ctrl |= I82544_CTRL_MDIO; else *_ctrl &= ~I82544_CTRL_MDIO; *_ctrl |= I82544_CTRL_MDIO_DIR; // drive the mdio line OUTL( *_ctrl, ioaddr + I82544_CTRL ); MII_PRINTF( "mii_write_data: " MII_STUFF ); MII_DELAY();}// Pass ioaddr around "invisibly"#define MII_INIT() cyg_uint32 _ctrl_val = mii_init(ioaddr); \ cyg_uint32 *_ctrl = &_ctrl_val;#define MII_CLOCK_UP() mii_clock_up(ioaddr, _ctrl)#define MII_CLOCK_DOWN() mii_clock_down(ioaddr, _ctrl)#define MII_READ_MODE() mii_read_mode(ioaddr, _ctrl)#define MII_READ_DATA_BIT() mii_read_data_bit(ioaddr, _ctrl)#define MII_WRITE_DATA_BIT( _d_ ) mii_write_data_bit(ioaddr,(_d_),_ctrl)// ------------------------------------------------------------------------//// MDIO//// Management data over the MII interface - nasty hand driven serial stuff//static void mii_write_bits( int ioaddr, int val, int bitcount, cyg_uint32 *_ctrl ){ int i; // These are deliberately signed ints so that we can send an overlong // preamble if we want by saying "send -1 of width 40 bits" and relying // on sign extension. for ( i = bitcount - 1; i >= 0; i-- ) { MII_WRITE_DATA_BIT( (val >> i) & 1 ); MII_DELAY(); MII_CLOCK_UP(); MII_CLOCK_DOWN(); }}static int mii_read_bits( int ioaddr, int bitcount, cyg_uint32 *_ctrl ){ int i; int val = 0; for ( i = bitcount - 1; i >= 0; i-- ) { MII_CLOCK_DOWN(); val <<= 1; val |= MII_READ_DATA_BIT(); MII_CLOCK_UP(); } return val;}#define MII_WRITE_BITS( val, bitcount ) mii_write_bits( ioaddr, val, bitcount, _ctrl )#define MII_READ_BITS( bitcount ) mii_read_bits( ioaddr, bitcount, _ctrl )// Now define subsections of the protocol in terms of the above#define MII_WRITE_PREAMBLE() MII_WRITE_BITS( -1, 32 ) // >32 x 1s#define MII_WRITE_START() MII_WRITE_BITS( 1, 2 ) // 01#define MII_WRITE_WRITE_CMD() MII_WRITE_BITS( 1, 2 ) // 01#define MII_WRITE_READ_CMD() MII_WRITE_BITS( 2, 2 ) // 10#define MII_WRITE_PHY_ADDR(_p_) MII_WRITE_BITS( _p_, 5 )#define MII_WRITE_REGNUM( _r_ ) MII_WRITE_BITS( (_r_), 5 )#define MII_WRITE_TURNAROUND() MII_WRITE_BITS( 2, 2 )#define MII_READ_TURNAROUND() CYG_MACRO_START \ MII_READ_MODE(); /* to turn off driving the line */ \ (void)(MII_READ_BITS( 2 )); /* discard TA "bits" */ \CYG_MACRO_END#define MII_IDLE() CYG_MACRO_START \ MII_READ_MODE(); /* to turn off driving the line */ \ ((void)MII_READ_BITS( 5 )); /* extra clocks in Hi-Z mode */ \ MII_CLOCK_DOWN(); \CYG_MACRO_END#define MII_READ_REGVAL() MII_READ_BITS( 16 )#define MII_WRITE_REGVAL( _v_ ) MII_WRITE_BITS( (_v_), 16 )static int mii_read_register( struct i82544 *p_i82544, int phy, int regnum ){ int value = 0; cyg_uint32 ioaddr = p_i82544->io_address; if( p_i82544->device == 0x1004 ) { // An 82543, read MII register via software defined pins in // CTRL register. MII_INIT(); MII_WRITE_PREAMBLE(); MII_WRITE_START(); MII_WRITE_READ_CMD(); MII_WRITE_PHY_ADDR(phy); MII_WRITE_REGNUM( regnum ); MII_READ_TURNAROUND(); value = MII_READ_REGVAL(); MII_IDLE(); } else { // Others, read MII register via MDIC register. cyg_uint32 mdic = (2<<26) | (phy<<21) | (regnum<<16); OUTL( mdic, ioaddr + I82544_MDIC ); // Wait for ready do { mdic = INL( ioaddr + I82544_MDIC ); } while( (mdic & (1<<28)) == 0 ); value = mdic & 0xFFFF; } return value;}#ifndef CYGHWR_DEVS_ETH_INTEL_I82544_USE_ASDstatic void mii_write_register( struct i82544 *p_i82544, int phy, int regnum, int value ){ cyg_uint32 ioaddr = p_i82544->io_address; if( p_i82544->device == 0x1004 ) { // An 82543, write MII register via software defined pins in // CTRL register. MII_INIT(); MII_WRITE_PREAMBLE(); MII_WRITE_START(); MII_WRITE_WRITE_CMD(); MII_WRITE_PHY_ADDR(phy); MII_WRITE_REGNUM( regnum ); MII_WRITE_TURNAROUND(); MII_WRITE_REGVAL( value ); MII_IDLE(); } else { // Others, write MII register via MDIC register. cyg_uint32 mdic = (1<<26) | (phy<<21) | (regnum<<16) | (value&0xFFFF); OUTL( mdic, ioaddr + I82544_MDIC ); // Wait for ready do { mdic = INL( ioaddr + I82544_MDIC ); } while( (mdic & (1<<28)) == 0 ); }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?