if_i82559.c
来自「开放源码实时操作系统源码.」· C语言 代码 · 共 1,724 行 · 第 1/5 页
C
1,724 行
// GIBENDIAN addressing; A0 and A1 are flipped:
#define RFD_STATUS 0
#define RFD_STATUS_LO 2 // swapped
#define RFD_STATUS_HI 0 // swapped
#define RFD_LINK 4
#define RFD_RDB_ADDR 8
#define RFD_COUNT 14 // swapped
#define RFD_SIZE 12 // swapped
#define RFD_BUFFER 16
#define RFD_SIZEOF 16
#endif // CYG_ADDRESSING_IS_GIBENDIAN
// ------------------------------------------------------------------------
//
// TRANSMIT FRAME DESCRIPTORS
//
// ------------------------------------------------------------------------
#if (CYG_BYTEORDER == CYG_MSBFIRST)
// Note that CMD/STATUS bits are endian converted - so we don't need
// to fiddle the byteorder when accessing the CMD/STATUS word!
#define TxCB_CMD_TRANSMIT 0x0400 // transmit command
#define TxCB_CMD_SF 0x0800 // 0=simplified, 1=flexible mode
#define TxCB_CMD_NC 0x0010 // 0=CRC insert by controller
#define TxCB_CMD_I 0x0020 // generate interrupt on completion
#define TxCB_CMD_S 0x0040 // suspend on completion
#define TxCB_CMD_EL 0x0080 // last command block in CBL
#define TxCB_COUNT_MASK 0x3fff
#define TxCB_COUNT_EOF 0x8000
#else // Little-endian layout
#define TxCB_COUNT_MASK 0x3fff
#define TxCB_COUNT_EOF 0x8000
#define TxCB_CMD_TRANSMIT 0x0004 // transmit command
#define TxCB_CMD_SF 0x0008 // 0=simplified, 1=flexible mode
#define TxCB_CMD_NC 0x0010 // 0=CRC insert by controller
#define TxCB_CMD_I 0x2000 // generate interrupt on completion
#define TxCB_CMD_S 0x4000 // suspend on completion
#define TxCB_CMD_EL 0x8000 // last command block in CBL
#endif // CYG_BYTEORDER
#ifndef CYG_ADDRESSING_IS_GIBENDIAN
// Normal addressing
#define TxCB_STATUS 0
#define TxCB_CMD 2
#define TxCB_LINK 4
#define TxCB_TBD_ADDR 8
#define TxCB_COUNT 12
#define TxCB_TX_THRESHOLD 14
#define TxCB_TBD_NUMBER 15
#define TxCB_BUFFER 16
#define TxCB_SIZEOF 16
#else // CYG_ADDRESSING_IS_GIBENDIAN
// GIBENDIAN addressing; A0 and A1 are flipped:
#define TxCB_STATUS 2 // swapped
#define TxCB_CMD 0 // swapped
#define TxCB_LINK 4
#define TxCB_TBD_ADDR 8
#define TxCB_COUNT 14 // swapped
#define TxCB_TX_THRESHOLD 13 // swapped
#define TxCB_TBD_NUMBER 12 // swapped
#define TxCB_BUFFER 16
#define TxCB_SIZEOF 16
#endif // CYG_ADDRESSING_IS_GIBENDIAN
// ------------------------------------------------------------------------
//
// STRUCTURES ADDED FOR PROMISCUOUS MODE
//
// ------------------------------------------------------------------------
#if (CYG_BYTEORDER == CYG_MSBFIRST)
// Note CFG CMD and STATUS swapped, so no need for endian conversion
// in code.
#define CFG_CMD_EL 0x0080
#define CFG_CMD_SUSPEND 0x0040
#define CFG_CMD_INT 0x0020
#define CFG_CMD_IAS 0x0100 // individual address setup
#define CFG_CMD_CONFIGURE 0x0200 // configure
#define CFG_CMD_MULTICAST 0x0300 // Multicast-Setup
#define CFG_STATUS_C 0x0080
#define CFG_STATUS_OK 0x0020
#else // Little-endian
#define CFG_CMD_EL 0x8000
#define CFG_CMD_SUSPEND 0x4000
#define CFG_CMD_INT 0x2000
#define CFG_CMD_IAS 0x0001 // individual address setup
#define CFG_CMD_CONFIGURE 0x0002 // configure
#define CFG_CMD_MULTICAST 0x0003 // Multicast-Setup
#define CFG_STATUS_C 0x8000
#define CFG_STATUS_OK 0x2000
#endif // CYG_BYTEORDER
#ifndef CYG_ADDRESSING_IS_GIBENDIAN
// Normal addressing
#define CFG_STATUS 0
#define CFG_CMD 2
#define CFG_CB_LINK_OFFSET 4
#define CFG_BYTES 8
#define CFG_SIZEOF 32
#else // CYG_ADDRESSING_IS_GIBENDIAN
// GIBENDIAN addressing; A0 and A1 are flipped:
#define CFG_STATUS 2
#define CFG_CMD 0
#define CFG_CB_LINK_OFFSET 4
#define CFG_BYTES 8
#define CFG_SIZEOF 32
#endif // CYG_ADDRESSING_IS_GIBENDIAN
// Normal addressing
#define CFG_MC_LIST_BYTES 8
#define CFG_MC_LIST_DATA 10
// ------------------------------------------------------------------------
//
// STATISTICAL COUNTER STRUCTURE
//
// ------------------------------------------------------------------------
#ifdef KEEP_STATISTICS
STATISTICS statistics[CYGNUM_DEVS_ETH_INTEL_I82559_DEV_COUNT];
I82559_COUNTERS i82559_counters[CYGNUM_DEVS_ETH_INTEL_I82559_DEV_COUNT];
#endif // KEEP_STATISTICS
// ------------------------------------------------------------------------
//
// 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_I82559_DEV_COUNT; i++) { \
if (i82559_netdev_array[i] == ndp) valid_netdev = 1; \
if (i82559_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_i82559 == i82559_sc_array[i]->driver_private, \
"sc pointer bad" ); \
CYG_MACRO_END
#else
#define CHECK_NDP_SC_LINK()
#endif
#define IF_BAD_82559( _p_ ) \
if (({ \
int i, valid_p = 0; \
for(i = 0; i < CYGNUM_DEVS_ETH_INTEL_I82559_DEV_COUNT; i++) { \
if (i82559_priv_array[i] == (_p_)) { \
valid_p = 1; \
break; \
} \
} \
CYG_ASSERT(valid_p, "Bad pointer-to-i82559"); \
(!valid_p); \
}))
// ------------------------------------------------------------------------
//
// Managing the memory that is windowed onto the PCI bus
//
// ------------------------------------------------------------------------
static cyg_uint32 i82559_heap_size;
static cyg_uint8 *i82559_heap_base;
static cyg_uint8 *i82559_heap_free;
static void *mem_reserved_ioctl = (void*)0;
// uncacheable memory reserved for ioctl calls
// ------------------------------------------------------------------------
//
// FUNCTION PROTOTYPES
//
// ------------------------------------------------------------------------
static int pci_init_find_82559s(void);
static void i82559_reset(struct i82559* p_i82559);
static void i82559_restart(struct i82559 *p_i82559);
static int eth_set_mac_address(struct i82559* p_i82559, cyg_uint8 *addr, int eeprom );
static void InitRxRing(struct i82559* p_i82559);
static void ResetRxRing(struct i82559* p_i82559);
static void InitTxRing(struct i82559* p_i82559);
static void ResetTxRing(struct i82559* p_i82559);
#if defined(CYGHWR_DEVS_ETH_INTEL_I82559_MISSED_INTERRUPT) || \
defined(CYGNUM_DEVS_ETH_INTEL_I82559_SEPARATE_MUX_INTERRUPT) || \
!defined(CYGPKG_IO_ETH_DRIVERS_STAND_ALONE)
static void
eth_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
#endif
static cyg_uint32
eth_isr(cyg_vector_t vector, cyg_addrword_t data);
static int i82559_configure(struct i82559* p_i82559, int promisc,
int oversized, int multicast_all);
#ifdef ETH_DRV_SET_MC_LIST
static int i82559_set_multicast(struct i82559* p_i82559,
int num_addrs,
cyg_uint8 *address_list );
#endif // ETH_DRV_SET_MC_ALL
#ifdef CYGPKG_DEVS_ETH_INTEL_I82559_WRITE_EEPROM
static void
program_eeprom(cyg_uint32 ioaddr, cyg_uint32 eeprom_size, cyg_uint8 *data);
static void
write_eeprom(long ioaddr, int location, int addr_len, unsigned short value);
static int
write_enable_eeprom(long ioaddr, int addr_len);
#endif
// debugging/logging only:
void dump_txcb(TxCB* p_txcb);
void DisplayStatistics(void);
void update_statistics(struct i82559* p_i82559);
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 i82559_stop( struct eth_drv_sc *sc );
// ------------------------------------------------------------------------
// utilities
// ------------------------------------------------------------------------
typedef enum {
WAIT_RU, // wait before RU cmd
WAIT_CU // wait before CU cmd
} cmd_wait_t;
static inline
void
wait_for_cmd_done(long scb_ioaddr, cmd_wait_t type)
{
register int status;
register int wait;
wait = 0x100000;
do status = INW(scb_ioaddr + SCBCmd) /* nothing */ ;
while( (0 != ((CU_CMD_MASK | RU_CMD_MASK) & status)) && --wait >= 0);
if ( wait <= 0 ) {
// Then we timed out; reset the device and try again...
OUTL(I82559_SELECTIVE_RESET, scb_ioaddr + SCBPort);
#ifdef CYGDBG_USE_ASSERTS
missed_interrupt.waitcmd_timeouts++;
#endif
wait = 0x100000;
do status = INW(scb_ioaddr + SCBCmd) /* nothing */;
while( (0 != ((CU_CMD_MASK | RU_CMD_MASK) & status)) && --wait >= 0);
}
// special case - don't complain about RUC_ADDR_LOAD as it doesn't clear
// on some silicon
if ( RUC_ADDR_LOAD != (status & RU_CMD_MASK) )
CYG_ASSERT( wait > 0, "wait_for_cmd_done: cmd busy" );
if (WAIT_CU == type) {
// Also check CU is idle
wait = 0x100000;
do status = INW(scb_ioaddr + SCBStatus) /* nothing */;
while( (status & CU_STATUS_MASK) && --wait >= 0);
if ( wait <= 0 ) {
// Then we timed out; reset the device and try again...
OUTL(I82559_SELECTIVE_RESET, scb_ioaddr + SCBPort);
#ifdef CYGDBG_USE_ASSERTS
missed_interrupt.waitcmd_timeouts_cu++;
#endif
wait = 0x100000;
do status = INW(scb_ioaddr + SCBCmd) /* nothing */;
while( (0 != ((CU_CMD_MASK | RU_CMD_MASK) & status)) && --wait >= 0);
}
CYG_ASSERT( wait > 0, "wait_for_cmd_done: CU busy" );
} else if (WAIT_RU == type) {
// Can't see any active state in the doc to check for
}
}
// ------------------------------------------------------------------------
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
Mask82559Interrupt(struct i82559* p_i82559)
{
int old = 0;
#ifdef CYGPRI_DEVS_ETH_INTEL_I82559_MASK_INTERRUPTS
CYGPRI_DEVS_ETH_INTEL_I82559_MASK_INTERRUPTS(p_i82559,old);
#else
// if (query_enabled)
old |= 1;
cyg_drv_interrupt_mask(p_i82559->vector);
#ifdef CYGNUM_DEVS_ETH_INTEL_I82559_SEPARATE_MUX_INTERRUPT
// if (query_enabled)
old |= 2;
cyg_drv_interrupt_mask(CYGNUM_DEVS_ETH_INTEL_I82559_SEPARATE_MUX_INTERRUPT);
#endif
#endif
/* it may prove necessary to do something like this
if ( mybits != (mybits & old) )
/# then at least one of them was disabled, so
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?