📄 if_ixdp2400.c
字号:
#define RFD_STATUS_LO_C 0x8000 // completion of received frame
#define RFD_STATUS_LO_OK 0x2000 // frame received with no errors
#define RFD_RX_CRC 0x00000800 // crc error
#define RFD_RX_ALIGNMENT 0x00000400 // alignment error
#define RFD_RX_RESOURCE 0x00000200 // out of space, no resources
#define RFD_RX_DMA_OVER 0x00000100 // DMA overrun
#define RFD_RX_SHORT 0x00000080 // short frame error
#define RFD_RX_LENGTH 0x00000020 //
#define RFD_RX_ERROR 0x00000010 // receive error
#define RFD_RX_NO_ADR_MATCH 0x00000004 // no address match
#define RFD_RX_IA_MATCH 0x00000002 // individual address does not match
#define RFD_RX_TCO 0x00000001 // TCO indication
typedef struct rbd {
volatile cyg_uint32 count:14, // bytes used in buffer
f:1, // buffer has been used (filled)
eof:1; // last receive buffer in frame
volatile cyg_uint32 next_rbd; // next RBD (RU base relative)
volatile cyg_uint32 buffer_address; // address of receive data buffer
volatile cyg_uint32 size:15, // size of the associated buffer
el:1; // buffer of this RBD is last
} RBD;
// ------------------------------------------------------------------------
//
// TRANSMIT FRAME DESCRIPTORS
//
// ------------------------------------------------------------------------
typedef struct txcb {
volatile cyg_uint32 txstatus:16, // result of transmit operation
command:16; // transmit command
volatile cyg_uint32 link; // offset from RU base to next RFD
volatile cyg_uint32 tbd_address; // pointer to Rx data buffer
#ifdef __ARMEB__
volatile cyg_uint32 tbd_number:8,
tx_threshold:8,
eof:1,
count:15;
#else
volatile cyg_uint32 count:15, // number of bytes in transmit buffer
eof:1,
tx_threshold:8,
tbd_number:8;
#endif
volatile cyg_uint8 buffer[0]; // data buffer (simple mode)
} TxCB;
#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
// ------------------------------------------------------------------------
//
// STRUCTURES ADDED FOR PROMISCUOUS MODE
//
// ------------------------------------------------------------------------
typedef struct {
cyg_uint32 cb_status_word:13,
cb_ok:1,
cb_dc:1,
cb_complete:1,
cb_cmd:3,
cb_cmd_word:10,
cb_int:1,
cb_suspend:1,
cb_el:1;
cyg_uint32 cb_link_offset;
} CB_STRUCT;
typedef struct {
CB_STRUCT cb_entry;
cyg_uint8 config_bytes[24];
} CONFIG_CMD_STRUCT;
// ------------------------------------------------------------------------
//
// STATISTICAL COUNTER STRUCTURE
//
// ------------------------------------------------------------------------
#ifdef KEEP_STATISTICS
STATISTICS statistics[2];
I82559_COUNTERS i82559_counters[2];
#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
// This is encapsulated here so that a change to > 2 interfaces can
// easily be accommodated.
#define IF_BAD_82559( _p_ ) \
CYG_ASSERT( (&i82559[0] == (_p_)) || (&i82559[1] == (_p_)), \
"Bad pointer-to-i82559" ); \
if ( (&i82559[0] != (_p_)) && (&i82559[1] != (_p_)) )
// ------------------------------------------------------------------------
// Instantiate the interfaces that we have:
// number of interfaces
#define MAX_82559 1
I82559 i82559[MAX_82559]; // i82559 device info. structure
// eth0
ETH_DRV_SC(ixdp2400_sc0,
&i82559[0], // Driver specific data
"eth0", // Name for this interface
i82559_start,
i82559_stop,
i82559_ioctl,
i82559_can_send,
i82559_send,
i82559_recv,
i82559_deliver,
i82559_poll,
i82559_int_vector
);
NETDEVTAB_ENTRY(ixdp2400_netdev0,
"ixdp2400-0",
ixdp2400_i82559_init,
&ixdp2400_sc0);
#if (MAX_82559 > 1)
// eth1
ETH_DRV_SC(ixdp2400_sc1,
&i82559[1], // Driver specific data
"eth1", // Name for this interface
i82559_start,
i82559_stop,
i82559_ioctl,
i82559_can_send,
i82559_send,
i82559_recv,
i82559_deliver,
i82559_poll,
i82559_int_vector
);
NETDEVTAB_ENTRY(ixdp2400_netdev1,
"ixdp2400-1",
ixdp2400_i82559_init,
&ixdp2400_sc1);
#else
int ixdp2400_netdev1 = -1; // for asserts about valid addresses
int ixdp2400_sc1 = -1;
#endif // eth1 is included
// This is in a macro so that if more devices arrive it can easily be changed
#define CHECK_NDP_SC_LINK() CYG_MACRO_START \
CYG_ASSERT( ((void *)ndp == (void *)&ixdp2400_netdev0) || \
((void *)ndp == (void *)&ixdp2400_netdev1), "Bad ndp" ); \
CYG_ASSERT( ((void *)sc == (void *)&ixdp2400_sc0) || \
((void *)sc == (void *)&ixdp2400_sc1), "Bad sc" ); \
CYG_ASSERT( (void *)p_i82559 == sc->driver_private, "sc pointer bad" );\
CYG_MACRO_END
externC cyg_uint32 board_rev;
extern struct board_config *board_config_data;
// ------------------------------------------------------------------------
//
// 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 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);
#ifdef CYGPKG_DEVS_ETH_ARM_IXDP2400_WRITE_EEPROM
static void program_eeprom(cyg_uint32 , cyg_uint32 , cyg_uint8 * );
#endif
#ifdef CYGPKG_NET
static int eth_set_promiscuous_mode(struct i82559* p_i82559);
#endif
// ------------------------------------------------------------------------
// We use this as a templete when writing a new MAC address into the
// eeproms. The MAC address in the first few bytes is over written
// with the correct MAC address and then the whole lot is programmed
// into the serial EEPROM. The checksum is calculated on the fly and
// sent instead of the last two bytes.
// The values are copied from the Intel EtherPro10/100+ &c devices
// in the EBSA boards.
#ifdef CYGPKG_DEVS_ETH_ARM_IXDP2400_WRITE_EEPROM
#define ee00 0x00, 0x00 // shorthand
static char eeprom_burn[126] = {
/* halfword addresses! */
/* 0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x04,
/* 4: */ ee00 , 0x01, 0x02, 0x01, 0x47, ee00 ,
/* 8: */ 0x97, 0x72, 0x05, 0x57, 0x80, 0x40, 0x00, 0x00,
/* C: */ 0x00, 0x00, ee00 , ee00 , ee00 ,
/* 10: */ ee00 , ee00 , ee00 , ee00 ,
/* 14: */ ee00 , ee00 , ee00 , ee00 ,
/* 18: */ ee00 , ee00 , ee00 , ee00 ,
/* 1C: */ ee00 , ee00 , ee00 , ee00 ,
/* 20: */ ee00 , ee00 , ee00 , ee00 ,
/* 24: */ ee00 , ee00 , ee00 , ee00 ,
/* 28: */ ee00 , ee00 , ee00 , ee00 ,
/* 2C: */ ee00 , ee00 , ee00 , ee00 ,
/* 30: */ 0x28, 0x01, ee00 , ee00 , ee00 ,
/* 34: */ ee00 , ee00 , ee00 , ee00 ,
/* 38: */ ee00 , ee00 , ee00 , ee00 ,
/* 3C: */ ee00 , ee00 , ee00
};
#undef ee00
#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);
// ------------------------------------------------------------------------
// utilities
// ------------------------------------------------------------------------
static // inline
void wait_for_cmd_done(long scb_ioaddr)
{
register int CSRstatus;
register int wait = 100000;
do
{
udelay(10);
#ifdef USE_MEM_ADRS
CSRstatus = INB(scb_ioaddr + SCBCmd) ; // Just read the command byte
#else
CSRstatus = INB(scb_ioaddr + SCBCmd +1) ; // Just read the command byte
#endif
}while( CSRstatus && --wait > 0);
CYG_ASSERT( wait > 0, "wait_for_cmd_done" );
}
// Short circuit the drv_interrupt_XXX API once we are started:
static inline int Mask82559Interrupt(struct i82559* p_i82559)
{
hal_interrupt_mask(p_i82559->vector);
return p_i82559->vector;
}
static inline void UnMask82559Interrupt(struct i82559* p_i82559, int old)
{
hal_interrupt_unmask(p_i82559->vector);
}
#ifdef CYGDBG_USE_ASSERTS // an indication of a debug build
static int acknowledge82559interrupt_compensating = 0;
#endif
static void Acknowledge82559Interrupt(struct i82559* p_i82559)
{
cyg_uint32 ioaddr;
cyg_uint16 status;
int loops = 64;
cyg_drv_interrupt_acknowledge(p_i82559->vector);
// It appears that some time can be taken before the interrupt source
// *really* quietens down... this is ugly, but effective.
// Without it, we get "Spurious Interrupt!" failures.
ioaddr = p_i82559->io_address; // get I/O address for 82559
status = INW(ioaddr + SCBStatus);
while ((0 != (status & SCB_INTACK_MASK)) && --loops >= 0) {
OUTW( status & SCB_INTACK_MASK, ioaddr + SCBStatus);
cyg_drv_interrupt_acknowledge(p_i82559->vector);
#ifdef CYGDBG_USE_ASSERTS
acknowledge82559interrupt_compensating++; // verify this is executed
#endif
status = INW(ioaddr + SCBStatus);
}
CYG_ASSERT( loops >= 0, "Acknowledge82559Interrupt" );
}
// ------------------------------------------------------------------------
// Memory management
//
// Simply carve off from the front of the PCI mapped window into real memory
static void *pciwindow_mem_alloc(int size)
{
void *p_memory;
int _size = size;
p_memory = (void *)0;
size = (size + 3) & ~3;
if ( (i82559_heap_free+size) < (i82559_heap_base+i82559_heap_size) ) {
cyg_uint32 *p;
p_memory = (void *)i82559_heap_free;
i82559_heap_free += size;
for ( p = (cyg_uint32 *)p_memory; _size > 0; _size -= 4 )
*p++ = 0;
}
else
{
printf("Couldn't get the PCI mapped memory window\n");
}
return p_memory;
}
// ------------------------------------------------------------------------
//
// GET EEPROM SIZE
//
// ------------------------------------------------------------------------
static int get_eeprom_size(long ioaddr)
{
unsigned short retval = 0;
int ee_addr = ioaddr + SCBeeprom;
int i, addrbits;
// Should already be not-selected, but anyway:
OUTW(EE_ENB & ~EE_CS, ee_addr);
eeprom_delay(EEPROM_ENABLE_DELAY);
OUTW(EE_ENB, ee_addr);
eeprom_delay(EEPROM_ENABLE_DELAY);
// Shift the read command bits out.
for (i = 2; i >= 0; i--) {
short dataval = (6 & (1 << i)) ? EE_DATA_WRITE : 0;
OUTW(EE_ENB | dataval , ee_addr);
eeprom_delay(EEPROM_SK_DELAY);
OUTW(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
eeprom_delay(EEPROM_SK_DELAY);
OUTW(EE_ENB | dataval , ee_addr);
eeprom_delay(EEPROM_SK_DELAY);
}
// Now clock out address zero, looking for the dummy 0 data bit
for ( i = 1; i <= 12; i++ ) {
OUTW(EE_ENB , ee_addr);
eeprom_delay(EEPROM_SK_DELAY);
OUTW(EE_ENB | EE_SHIFT_CLK, ee_addr);
eeprom_delay(EEPROM_SK_DELAY);
OUTW(EE_ENB , ee_addr);
eeprom_delay(EEPROM_SK_DELAY);
retval = INW(ee_addr) & EE_DATA_READ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -