📄 if_8139.c
字号:
#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
/*
* If this driver was not compiled in stand alone (without interrupts)
* mode, enable interrupts.
*/
OUTW(RLTK8139_IRQ, rltk8139_info->base_address + IMR);
#endif
#ifdef DEBUG_RLTK8139_DRIVER
rltk8139_print_state(sc);
#endif
}
/*
* Stop the chip, disabling the transmitter and receiver.
*/
static void
rltk8139_stop(struct eth_drv_sc *sc)
{
Rltk8139_t *rltk8139_info;
#ifdef DEBUG_RLTK8139_DRIVER
diag_printf("rltk8139_stop(%s)\n", sc->dev_name);
#endif
rltk8139_info = (Rltk8139_t *)(sc->driver_private);
/* Disable receiver and transmitter */
OUTB(INB(rltk8139_info->base_address + CR) & ~(TE|RE),
rltk8139_info->base_address + CR);
/* Mask all interrupts */
OUTW(0, rltk8139_info->base_address + IMR);
}
/*
* 8139 control function. Unlike a 'real' ioctl function, this function is
* not required to tell the caller why a request failed, only that it did
* (see the eCos documentation).
*/
static int
rltk8139_control(struct eth_drv_sc *sc, unsigned long key, void *data,
int data_length)
{
int i;
Rltk8139_t *rltk8139_info;
#ifdef CYGPKG_DEVS_ETH_RLTK_8139_WRITE_EEPROM
cyg_uint16 WrData, RdData;
cyg_uint8 *pSrcData;
int iRetry;
#endif
#ifdef DEBUG_RLTK8139_DRIVER
diag_printf("rltk8139_control(%08x, %lx)\n", sc, key);
#endif
rltk8139_info = (Rltk8139_t *)(sc->driver_private);
switch (key) {
#ifdef ETH_DRV_SET_MAC_ADDRESS
case ETH_DRV_SET_MAC_ADDRESS:
if ( 6 != data_length )
return 1;
/* Set the mac address */
for (i = 0; i < 6; ++i) {
rltk8139_info->mac[i] = *(((cyg_uint8 *)data) + i);
OUTB(rltk8139_info->mac[i], rltk8139_info->base_address + IDR0 + i);
}
#ifdef CYGPKG_DEVS_ETH_RLTK_8139_WRITE_EEPROM
pSrcData = (cyg_uint8 *)data;
for(i = 0; i < 3; i++){
WrData = ((cyg_uint16)(*pSrcData++)) & 0xff;
WrData |= ((cyg_uint16)(*pSrcData++)) << 8;
for( iRetry = 0; iRetry < 3; iRetry++){
rltk8139_eeprom_write(
(char *)(rltk8139_info->base_address + CR9346),
EEPROM_CMD_WRITE, i + 7, WrData);
RdData = rltk8139_eeprom_read(
(char *)(rltk8139_info->base_address + CR9346),
EEPROM_CMD_READ, i + 7);
if( RdData == WrData ){
break;
}
}
}
#endif
return 0;
#endif
#ifdef ETH_DRV_GET_MAC_ADDRESS
case ETH_DRV_GET_MAC_ADDRESS:
if (6 != data_length)
return 1;
memcpy(data, rltk8139_info->mac, 6);
return 0;
#endif
#ifdef ETH_DRV_GET_IF_STATS_UD
case ETH_DRV_GET_IF_STATS_UD: // UD == UPDATE
//ETH_STATS_INIT( sc ); // so UPDATE the statistics structure
#endif
// drop through
#ifdef ETH_DRV_GET_IF_STATS
case ETH_DRV_GET_IF_STATS:
#endif
#if defined(ETH_DRV_GET_IF_STATS) || defined (ETH_DRV_GET_IF_STATS_UD)
break;
#endif
#ifdef ETH_DRV_SET_MC_LIST
case ETH_DRV_SET_MC_LIST:
/*
* Program the 8139's multicast filter register. If the eth_drv_mc_list
* contains at least one element, set the accept multicast bit in the
* receive config register.
*/
rltk8139_set_multicast_list(rltk8139_info, (struct eth_drv_mc_list *)data);
if (((struct eth_drv_mc_list *)data)->len > 0)
OUTL(INL(rltk8139_info->base_address + RCR) | AM,
rltk8139_info->base_address + RCR);
else
OUTL(INL(rltk8139_info->base_address + RCR) & ~AM,
rltk8139_info->base_address + RCR);
return 0;
#endif // ETH_DRV_SET_MC_LIST
#ifdef ETH_DRV_SET_MC_ALL
case ETH_DRV_SET_MC_ALL:
/*
* Set the accept multicast bit in the receive config register and
* program the multicast filter to accept all addresses.
*/
rltk8139_set_multicast_list(rltk8139_info, NULL);
OUTL(INL(rltk8139_info->base_address + RCR) | AM,
rltk8139_info->base_address + RCR);
return 0;
#endif // ETH_DRV_SET_MC_ALL
default:
return 1;
}
return 1;
}
/*
* Check if a new packet can be sent.
*/
static int
rltk8139_can_send(struct eth_drv_sc *sc)
{
return ((Rltk8139_t *)(sc->driver_private))->tx_num_free_desc;
}
/*
* Send a packet over the wire.
*/
static void
rltk8139_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len,
int total_len, unsigned long key)
{
Rltk8139_t *rltk8139_info;
cyg_uint8 *tx_buffer;
struct eth_drv_sg *last_sg;
int desc;
rltk8139_info = (Rltk8139_t *)(sc->driver_private);
#ifdef DEBUG_RLTK8139_DRIVER
diag_printf("rltk8139_send(%s, %08x, %d, %d, %08lx)\n",
sc->dev_name, sg_list, sg_len, total_len, key);
#endif
CYG_ASSERT(total_len <= TX_BUF_SIZE, "packet too long");
/*
* Get the next free descriptor to send. We lock out all interrupts
* and scheduling because we really, really do not want to be interrupted
* at this point.
*
* IMPORTANT NOTE: the RealTek data sheet does not really make this clear,
* but when they talk about a 'ring' of transmit descriptors, they
* _really_ mean it, i.e. you _must_ use descriptor #1 after descriptor
* #0 even if transmission of descriptor #0 has already completed.
*/
cyg_drv_isr_lock();
/*
* Sanity check to see if '_send' was called even though there is no free
* descriptor. This is probably unnecessary.
*/
if (rltk8139_info->tx_num_free_desc == 0) {
cyg_drv_isr_unlock();
#ifdef DEBUG_RLTK8139_DRIVER
diag_printf("rltk8139_send(%s): no free descriptor available\n",
sc->dev_name);
#endif
return;
}
/*
* Get the free descriptor and advance the descriptor counter modulo
* TX_NUM_DESC. We assume that TX_NUM_DESC will always be a power of 2.
*/
desc = rltk8139_info->tx_free_desc;
rltk8139_info->tx_free_desc = (rltk8139_info->tx_free_desc + 1)
& (NUM_TX_DESC - 1);
/* Decrement the number of free descriptors */
rltk8139_info->tx_num_free_desc -= 1;
/* Reenable interrupts at this point */
cyg_drv_isr_unlock();
/*
* Determine the buffer memory to use and tell the hardware about it.
* Since we use fixed buffer addresses, we do not need to set up TSADx.
* Memorize the key so we can call the tx_done callback correctly.
*
* While it would be possible to set TSADx to the packet directly if
* it is stored in a linear memory area with 32 bit alignment, it seems
* this happens so seldomly that it's simply not worth the extra
* runtime check.
*/
tx_buffer = (cyg_uint8 *)CYGARC_UNCACHED_ADDRESS(rltk8139_info->tx_buffer
+ TX_BUF_SIZE * desc);
rltk8139_info->tx_desc_key[desc] = key;
/*
* Copy the data to the designated position. Note that unlike the eCos
* Intel 82559 driver, we simply assume that all the scatter/gather list
* elements' lengths will add up to total_len exactly, and don't check
* to make sure.
*/
for (last_sg = &sg_list[sg_len]; sg_list < last_sg; ++sg_list) {
memcpy(tx_buffer, (void *)(sg_list->buf), sg_list->len);
tx_buffer += sg_list->len;
}
/*
* Make sure the packet has the minimum ethernet packet size, padding
* with zeros if necessary.
*/
if (total_len < MIN_ETH_FRAME_SIZE) {
memset(tx_buffer, 0, MIN_ETH_FRAME_SIZE - total_len);
total_len = MIN_ETH_FRAME_SIZE;
}
/*
* Flush the data cache here if necessary. This ensures the 8139 can
* read the correct data from the transmit buffer.
*/
#ifdef CYGPKG_DEVS_ETH_RLTK_8139_SOFTWARE_CACHE_COHERENCY
HAL_DCACHE_FLUSH(rltk8139_info->tx_buffer + TX_BUF_SIZE * desc, total_len);
#endif
/*
* Now setup the correct transmit descriptor to actually send the data.
* The early TX threshold is incremented by the driver until we reach a
* size that prevents transmit underruns. (An earlier attempt to calculate
* this parameter from the packet size didn't work).
*/
OUTL((rltk8139_info->tx_threshold << ERTXTH_SHIFT) | (total_len & SIZE),
rltk8139_info->base_address + TSD0 + (desc<<2));
}
/*
* This routine actually retrieves data from the receive ring by
* copying it into the specified scatter/gather buffers. Again,
* we assume the scatter/gather list is OK and don't check against
* total length.
*/
static void
rltk8139_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list,
int sg_len)
{
Rltk8139_t *rltk8139_info;
struct eth_drv_sg *last_sg;
cyg_uint8 *rx_buffer;
rltk8139_info = (Rltk8139_t *)(sc->driver_private);
rx_buffer = rltk8139_info->rx_current;
/*
* Invalidate the cache line(s) mapped to the receive buffer
* if necessary.
*/
#ifdef CYGPKG_DEVS_ETH_RLTK_8139_SOFTWARE_CACHE_COHERENCY
HAL_DCACHE_INVALIDATE(rx_buffer, rltk8139_info->rx_size);
#endif
for (last_sg = &sg_list[sg_len]; sg_list < last_sg; ++sg_list) {
if (sg_list->buf != (CYG_ADDRESS)0) {
memcpy((void *)(sg_list->buf), rx_buffer, sg_list->len);
rx_buffer += sg_list->len;
}
}
}
/*
* This function does all the heavy lifting associated with interrupts.
*/
static void
rltk8139_deliver(struct eth_drv_sc *sc)
{
Rltk8139_t *rltk8139_info;
cyg_uint16 status, pci_status;
cyg_uint32 tsd;
int desc;
rltk8139_info = (Rltk8139_t *)(sc->driver_private);
/*
* The RealTek data sheet claims that reading the ISR will clear
* it. This is incorrect; to clear a bit in the ISR, a '1' must be
* written to the ISR instead. We immediately clear the interrupt
* bits at this point.
*/
status = INW(rltk8139_info->base_address + ISR);
OUTW(status, rltk8139_info->base_address + ISR);
#ifdef DEBUG_RLTK8139_DRIVER
diag_printf("rltk8139_deliver(%s): %04x\n", sc->dev_name, status);
#endif
/*
* Check for a PCI error. This seems like a very serious error to
* me, so we will reset the chip and hope for the best.
*/
if (status & IR_SERR) {
cyg_pci_read_config_uint16(rltk8139_info->pci_device_id,
CYG_PCI_CFG_STATUS, &pci_status);
cyg_pci_write_config_uint16(rltk8139_info->pci_device_id,
CYG_PCI_CFG_STATUS, pci_status);
#ifdef DEBUG_RLTK8139_DRIVER
diag_printf("rltk8139_deliver(%s): PCI error %04x\n",
sc->dev_name, pci_status);
#endif
rltk8139_reset(sc);
return;
}
/* Check for transmission complete (with errors or not) */
if ((status & IR_TER) || (status & IR_TOK)) {
/*
* Figure out which descriptors' status must be checked. We lock out
* interrupts while manipulating the descriptor list because we do not
* want to be interrupted at this point.
*/
while (1) {
cyg_drv_isr_lock();
/* Check if all descriptors are ready, in which case we are done. */
if (rltk8139_info->tx_num_free_desc >= NUM_TX_DESC) {
cyg_drv_isr_unlock();
break;
}
desc = (rltk8139_info->tx_free_desc
- (NUM_TX_DESC - rltk8139_info->tx_num_free_desc))
& (NUM_TX_DESC - 1);
cyg_drv_isr_unlock();
/* Get the current status of the descriptor */
tsd = INL(rltk8139_info->base_address + TSD0 + (desc<<2));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -