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 + -
显示快捷键?