📄 if_8139.c
字号:
/*
* If a transmit FIFO underrun occurred, increment the threshold
* value.
*/
if ((tsd & TUN) && (rltk8139_info->tx_threshold < 64))
rltk8139_info->tx_threshold += 1;
/*
* Check if a transmission completed OK. RealTek's data sheet implies
* that a successful transmission that experiences underrun will only
* set TUN. This is not true; TOK is set for all successful
* transmissions.
*/
if (tsd & TOK) {
(sc->funs->eth_drv->tx_done)(sc, rltk8139_info->tx_desc_key[desc], 0);
}
else if (tsd & TABT) {
/*
* Set the CLRABT bit in TCR. Since I haven't encountered any
* transmission aborts so far, I don't really know if this code
* will work or not.
*/
OUTL(INL(rltk8139_info->base_address + TCR) & CLRABT,
rltk8139_info->base_address + TCR);
(sc->funs->eth_drv->tx_done)(sc, rltk8139_info->tx_desc_key[desc], -1);
}
else {
/*
* This descriptor is not ready. Since the descriptors are used
* in a ring, this means that no more descriptors are ready.
*/
break;
}
/*
* Clear the saved key value. This is not really necessary, since
* the key value is never used to determine if a descriptor is
* valid or not. However, clearing it is a tidier IMO.
*/
rltk8139_info->tx_desc_key[desc] = 0;
/*
* Increment the free descriptor count and go through the loop again
* to see if more descriptors are ready.
*/
cyg_drv_isr_lock();
rltk8139_info->tx_num_free_desc += 1;
cyg_drv_isr_unlock();
}
}
if (status & IR_ROK) {
/*
* Received a frame. Note that '_deliver' does not actually copy any
* data; it just determines how many bytes are available and tells
* the generic ethernet driver about it, which then calls into
* the '_recv' function to copy the data.
*/
cyg_uint16 rx_pos;
cyg_uint32 header, length;
/*
* CAPR contains the index into the receive buffer. It is controlled
* completely in software. For some reason, CAPR points 16 bytes
* before the actual start of the packet.
*/
rx_pos = (INW(rltk8139_info->base_address + CAPR) + 16) % RX_BUF_LEN;
/*
* Loop until the rx buffer is empty. I have no idea how the 8139
* determines if the buffer still contains a packet; it may check
* that CAPR points 16 bytes before CBR.
*/
while (!(INB(rltk8139_info->base_address + CR) & BUFE)) {
/*
* Invalidate the data cache for the cache line containing the header
* if necessary.
*/
#ifdef CYGPKG_DEVS_ETH_RLTK_8139_SOFTWARE_CACHE_COHERENCY
HAL_DCACHE_INVALIDATE(&rltk8139_info->rx_ring[rx_pos],
sizeof(cyg_uint32));
#endif
/*
* The 8139 prepends each packet with a 32 bit packet header that
* contains a 16 bit length and 16 bit status field, in little-endian
* byte order.
*/
header = HAL_LE32TOC(*((volatile cyg_uint32 *)CYGARC_UNCACHED_ADDRESS(&rltk8139_info->rx_ring[rx_pos])));
/*
* If the 8139 is still copying data for this packet into the
* receive ring, it will set packet length to 0xfff0. This shouldn't
* ever happen because we do not use early receive.
*/
if ((header >> 16) == 0xFFF0)
break;
/*
* Since the 8139 appends the ethernet CRC to every packet, we
* must subtract 4 from the length to get the true packet length.
*/
length = (header >> 16) - 4;
/*
* Check if the packet was received correctly. The OpenBSD driver
* resets the chip if this is not the case; we attempt to salvage
* following packets by doing nothing.
*/
if (!(header & HDR_ROK)) {
}
else {
/*
* Packet was received OK. Determine from where to start copying
* bytes. This is saved in the driver private area so rlt8139_recv
* doesn't have to redetermine this information. Then, inform
* the generic ethernet driver about the packet.
*/
rltk8139_info->rx_current =
(cyg_uint8 *)CYGARC_UNCACHED_ADDRESS(rltk8139_info->rx_ring +
rx_pos + 4);
rltk8139_info->rx_size = length;
/* Tell eCos about the packet */
(sc->funs->eth_drv->recv)(sc, length);
}
/*
* Update CAPR. CAPR must be aligned to a 32 bit boundary, and should
* point 16 bytes before it's actual position.
*/
rx_pos = ((rx_pos + length + 8 + 3) & ~3) % RX_BUF_LEN;
OUTW((rx_pos - 16) % RX_BUF_LEN, rltk8139_info->base_address + CAPR);
}
}
if (status & IR_RXOVW) {
/*
* In case of a receive buffer overflow, the RealTek data sheet claims we
* should update CAPR and then write a '1'爐o ROK in ISR. However, none of
* the other 8139 drivers I have looked at do this, so we will just reset
* the chip instead.
*/
#ifdef DEBUG_RLTK8139_DRIVER
diag_printf("rltk8139_deliver(%s): receive buffer overflow\n",
sc->dev_name);
#endif
rltk8139_reset(sc);
return;
}
if (status & IR_FOVW) {
/*
* Rx FIFO overflow. According to RealTek's data sheet, this is cleared
* by writing a '1' to RXOVW. Again, none of the 8139 drivers I have
* seen actually do this, so we reset the chip instead.
*/
#ifdef DEBUG_RLTK8139_DRIVER
diag_printf("rltk8139_deliver(%s): receive FIFO overflow\n",
sc->dev_name);
#endif
rltk8139_reset(sc);
return;
}
if (status & IR_FUN) {
/*
* Packet underrun or link change interrupt.
* A cable was packet underrun or re-connected ?
*/
#ifdef DEBUG_RLTK8139_DRIVER
diag_printf("rltk8139_deliver(%s): packet underrun or link change\n",
sc->dev_name);
#endif
}
#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
/* Finally, reenable interrupts */
#ifdef CYGPKG_DEVS_ETH_RLTK_8139_MASK_INTERRUPTS_IN_8139
OUTW(RLTK8139_IRQ, rltk8139_info->base_address + IMR);
#else
cyg_interrupt_unmask(rltk8139_info->vector);
#endif
#endif
}
/*
* '_poll' does the same thing as '_deliver'. It is called periodically when
* the ethernet driver is operated in non-interrupt mode, for instance by
* RedBoot.
*/
static void
rltk8139_poll(struct eth_drv_sc *sc)
{
Rltk8139_t *rltk8139_info;
cyg_uint16 isr;
#ifdef DEBUG_RLTK8139_DRIVER
diag_printf("rltk8139_poll(%s)\n", sc->dev_name);
#endif
rltk8139_info = (Rltk8139_t *)(sc->driver_private);
/*
* Get the current interrupt status. If anything changed, call
* _deliver.
*/
if ((isr = INW(rltk8139_info->base_address + ISR)))
rltk8139_deliver(sc);
}
/*
* Return the interrupt vector used by this device.
*/
static int
rltk8139_int_vector(struct eth_drv_sc *sc)
{
return ((Rltk8139_t *)(sc->driver_private))->vector;
}
/*
* Quick and dirty register dump. This is somewhat dangerous, since
* we read the register space 32 bits at a time, regardless of actual
* register sizes.
*/
#ifdef DEBUG_RLTK8139_DRIVER
void
rltk8139_print_state(struct eth_drv_sc *sc) {
int i;
Rltk8139_t *rltk8139_info;
rltk8139_info = (Rltk8139_t *)(sc->driver_private);
for (i = IDR0; i < FFER; i += 16) {
diag_printf("8139 reg address 0x%02x = 0x%08x", i,
INL(rltk8139_info->base_address + i));
diag_printf(" 0x%08x", INL(rltk8139_info->base_address + i + 4));
diag_printf(" 0x%08x", INL(rltk8139_info->base_address + i + 8));
diag_printf(" 0x%08x\n", INL(rltk8139_info->base_address + i + 12));
}
}
#endif
#ifdef CYGPKG_DEVS_ETH_RLTK_8139_WRITE_EEPROM
/*
* Read mac_address from EEPROM.
*/
static cyg_uint16
rltk8139_eeprom_read( char *rtl_addr, cyg_uint8 eeprom_cmd, cyg_uint8 eeprom_addr )
{
cyg_uint8 read_data; // read from eeprom bit data
cyg_uint8 org_param; // original register parameter
cyg_uint8 mask_bit8; // mask bit
int icount; // for loop counter
// get old parameter
HAL_READ_UINT8( rtl_addr, org_param );
// ready
EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON );
// set command
mask_bit8 = 0x04;
for(icount = 0; icount < 3; icount++){
EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS | EEPROM_MASK( mask_bit8, eeprom_cmd ));
mask_bit8 >>= 1;
}
// set address
mask_bit8 = 0x20;
for(icount = 0; icount < 6; icount++){
EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS | EEPROM_MASK( mask_bit8, eeprom_addr ));
mask_bit8 >>= 1;
}
// read data
read_data = 0;
for(icount = 0; icount < 16; icount++){
EEPROM_RD_DATA( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS, read_data );
}
// close
EEPROM_WR_DATA( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS );
EEPROM_WR_DATA( rtl_addr, EEPROM_PG_ON );
// put old parameter
HAL_WRITE_UINT8(rtl_addr, org_param);
return(read_data);
}
/*
* Write in mac_address at EEPROM.
*/
static void
rltk8139_eeprom_write( char *rtl_addr, cyg_uint8 eeprom_cmd, cyg_uint8 eeprom_addr, cyg_uint16 src_data )
{
cyg_uint8 read_data; // read from eeprom bit data
cyg_uint8 org_param; // original register parameter
cyg_uint8 mask_bit8; // mask bit
cyg_uint16 mask_bit16; // mask bit for write data
int icount; // for loop counter
// get old parameter
HAL_READ_UINT8( rtl_addr, org_param );
// ready
EEPROM_WR_DATA( rtl_addr, EEPROM_PG_ON );
EEPROM_WR_DATA( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EESK );
EEPROM_WR_DATA( rtl_addr, EEPROM_PG_ON );
// set EWEN (eeprom write enable)
EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS | EEPROM_PG_EEDI );
EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS );
EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS );
EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS | EEPROM_PG_EEDI );
EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS | EEPROM_PG_EEDI );
EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS );
EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS );
EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS );
EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS );
EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON );
// set command
mask_bit8 = 0x04;
for(icount = 0; icount < 3; icount++){
EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS | EEPROM_MASK( mask_bit8, eeprom_cmd ));
mask_bit8 >>= 1;
}
// set address
mask_bit8 = 0x20;
for(icount = 0; icount < 6; icount++){
EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS | EEPROM_MASK( mask_bit8, eeprom_addr ));
mask_bit8 >>= 1;
}
// set data
mask_bit16 = 0x8000;
for(icount = 0; icount < 16; icount++){
EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS | EEPROM_MASK( mask_bit16, src_data ));
mask_bit16 >>= 1;
}
// close
EEPROM_WR_DATA( rtl_addr, EEPROM_PG_ON );
EEPROM_WR_DATA( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EESK );
EEPROM_WR_DATA( rtl_addr, EEPROM_PG_ON );
// write ready check
EEPROM_WR_DATA( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS );
// wait busy disable
icount = 0;
while( 1 ){
cyg_thread_delay( 1 );
HAL_WRITE_UINT8( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS | EEPROM_PG_EESK );
HAL_WRITE_UINT8( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS );
HAL_READ_UINT8( rtl_addr, read_data );
if(( read_data & EEPROM_PG_EEDO ) != 0 ){
break;
}
if( icount++ >= EEPROM_WR_BUSY_RETRIES ){
diag_printf("EEPROM write wait error adr=0x%02x data=0x%04x\n", eeprom_addr, src_data );
break;
}
}
HAL_WRITE_UINT8( rtl_addr, EEPROM_PG_ON );
// put old parameter
HAL_WRITE_UINT8( rtl_addr, org_param );
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -