if_i82544.c

来自「开放源码实时操作系统源码.」· C语言 代码 · 共 2,053 行 · 第 1/5 页

C
2,053
字号
#define I82544_RD_CSUM          10
#define I82544_RD_STATUS        12
#define I82544_RD_ERRORS        13
#define I82544_RD_SPECIAL       14
#define I82544_RD_SIZE          16

#define I82544_RD_STATUS_DD     (1<<0)
#define I82544_RD_STATUS_EOP    (1<<1)
#define I82544_RD_STATUS_IXSM   (1<<2)
#define I82544_RD_STATUS_VP     (1<<3)
#define I82544_RD_STATUS_TCPCS  (1<<5)
#define I82544_RD_STATUS_IPCS   (1<<6)
#define I82544_RD_STATUS_PIF    (1<<7)

// ------------------------------------------------------------------------
//
//               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_uint32
eth_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 void
udelay(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 void
UnMask82544Interrupt(struct i82544* p_i82544, int old)
{
    if (old & 1)
        cyg_drv_interrupt_unmask(p_i82544->vector);
}


static inline void
Acknowledge82544Interrupt(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 memory

static CYG_ADDRESS
pciwindow_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
#endif

static 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_ASD
static void mii_write_register( struct i82544 *p_i82544, int phy, int regnum, int value )
{
    cyg_uint32 ioaddr = p_i82544->io_address;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?