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