📄 rtl8139.c
字号:
static void rtl8139_weird_interrupt(struct rtl_private_data *private_data)
{
#ifdef DEBUG_RTL8139
debug_print("enter weird_interrupt process \r\n !");
#endif
return;
}
static void rtl8139_tx_interrupt (struct rtl_private_data *private_data)
{
// unsigned long txstatus;
debug_print("rtl_tx_inter() \r\n");
#ifdef DEBUG_RTL8139
debug_print("enter tx_interrupt process ! \r\n ");
#endif
// txstatus = RTL_R32 (TxStatus0);
/* Clear timeout flag */
#ifdef DEBUG_RTL8139
debug_print("interrupt from %s \r\n",private_data->nic->name);
#endif
private_data->nic->timeout = 0;
return;
}
int rtl_interrupt(void *arg)
{
struct rtl_private_data *private_data = (struct rtl_private_data *)arg;
struct nic *nic = private_data->nic;
int ackstat, status;
int boguscnt = max_interrupt_work;
int link_changed = 0; /* avoid bogus "uninit" warning */
/* Mask the bit that says "this is an io addr" */
ioaddr = nic->ioaddr;
do {
status = RTL_R16 (IntrStatus);
/* h/w no longer present (hotplug?) or major error, bail */
if (status == 0xFFFF)
break;
if ((status &
(PCIErr | PCSTimeout | RxUnderrun | RxOverflow |
RxFIFOOver | TxErr | TxOK | RxErr | RxOK)) == 0)
break;
/* Acknowledge all of the current interrupt sources ASAP, but
an first get an additional status bit from CSCR. */
if (status & RxUnderrun)
link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit;
ackstat = status & ~(RxAckBits | TxErr);
RTL_W16 (IntrStatus, ackstat);
#ifdef DEBUG_RTL8139
debug_print("interrupt status=%#4.4x ackstat=%#4.4x new intstat=%#4.4x.\r\n",
status,ackstat, RTL_R16 (IntrStatus));
#endif
if (status & RxAckBits)
rtl8139_rx_interrupt (private_data);
/* Check uncommon events with one test. */
if (status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow |
RxFIFOOver | RxErr))
rtl8139_weird_interrupt (private_data);
if (status & (TxOK | TxErr)) {
rtl8139_tx_interrupt (private_data);
if (status & TxErr)
RTL_W16 (IntrStatus, TxErr);
}
boguscnt--;
}while (boguscnt > 0);
if (boguscnt <= 0) {
#ifdef DEBUG_RTL8139
debug_print ("Too much work at interrupt, "
"IntrStatus=0x%4.4x.\n", status);
#endif
/* Clear all interrupt sources. */
RTL_W16 (IntrStatus, 0xffff);
}
_outp( ICR_A, EOI );
_outp( ICR_B, EOI );
return 0;
}
int
rtl8139_probe(struct nic *nic)
{
int i;
struct pci_device *p = NULL;
int speed10, fullduplex;
int found = 0;
p = lookup_pci_device(PCI_VENDOR_ID_REALTEK,PCI_DEVICE_ID_REALTEK_8139);
while(p&& found < N_RTL8139){
nic->pci_data = p;
#ifdef USE_IO_OPS
nic->ioaddr = p->ioaddr & ~3;
#else
nic->ioaddr = p->membase;
#endif
nic->irq = p->irq;
nic->device = p->device;
nic->vendor = p->vendor;
/*
* This bit below is not necessary at all since the pci.c subsystem
* is supposed to find the NIC, but I will leave it in since it
* hardly will ever execute this test.
*/
if (nic->ioaddr == 0) {
return -1;
}
/* Mask the bit that says "this is an io addr" */
ioaddr = nic->ioaddr;
/* Bring the chip out of low-power mode. */
RTL_W8(Cfg9346,0x00);
if (read_eeprom(0) != 0xffff) {
unsigned short *ap = (unsigned short*)nic->node_addr;
for (i = 0; i < 3; i++)
*ap++ = read_eeprom(i + 7);
} else {
unsigned char *ap = (unsigned char*)nic->node_addr;
for (i = 0; i < ETH_ALEN; i++)
*ap++ = RTL_R8(MAC0 + i);
}
speed10 = RTL_R8(MediaStatus) & MSRSpeed10;
fullduplex = RTL_R16(MII_BMCR) & BMCRDuplex;
debug_print("ioaddr %lX, addr %02x:%02x:%02x:%02x:%02x:%02x %sMbps %s-duplex\r\n",
ioaddr,
nic->node_addr[0],
nic->node_addr[1],
nic->node_addr[2],
nic->node_addr[3],
nic->node_addr[4],
nic->node_addr[5],
speed10 ? "10" : "100",
fullduplex ? "full" : "half");
rtl_reset(nic);
IRQ_REQUEST(nic->irq,rtl_interrupt,&private_datas[found]);
private_datas[found].nic = nic;
nic->watchdog = rtl_reset;
nic->transmit = rtl_transmit;
nic->ioctl = rtl_ioctl;
found ++;
nic ++;
p = p->next;
}
return found;
}
static void rtl_reset(struct nic* nic)
{
int i;
/* Mask the bit that says "this is an io addr" */
ioaddr = nic->ioaddr;
RTL_W8(ChipCmd,CmdReset);
cur_rx = 0;
cur_tx = 0;
/* Give the chip 10ms to finish the reset. */
load_timer2(10*TICKS_PER_MS);
while ((RTL_R8(ChipCmd) & CmdReset) != 0 && timer2_running())
/* wait */;
for (i = 0; i < ETH_ALEN; i++)
RTL_W8(MAC0 + i,nic->node_addr[i]);
/* Must enable Tx/Rx before setting transfer thresholds! */
RTL_W8(ChipCmd,CmdRxEnb | CmdTxEnb);
RTL_W32(RxConfig,(RX_FIFO_THRESH<<13) | (RX_BUF_LEN_IDX<<11) | (RX_DMA_BURST<<8)); /* accept no frames yet! */
RTL_W32(TxConfig,(TX_DMA_BURST<<8)|0x03000000);
/* The Linux driver changes Config1 here to use a different LED pattern
* for half duplex or full/autodetect duplex (for full/autodetect, the
* outputs are TX/RX, Link10/100, FULL, while for half duplex it uses
* TX/RX, Link100, Link10). This is messy, because it doesn't match
* the inscription on the mounting bracket. It should not be changed
* from the configuration EEPROM default, because the card manufacturer
* should have set that to match the card. */
RTL_W32(RxBuf,(unsigned long)rx_ring);
/* Start the chip's Tx and Rx process. */
RTL_W32(RxMissed,0);
/* set_rx_mode */
RTL_W8(RxConfig,AcceptBroadcast|AcceptMyPhys/*|AcceptAllPhys*/);
/* If we add multicast support, the MAR0 register would have to be
* initialized to 0xffffffffffffffff (two 32 bit accesses). Etherboot
* only needs broadcast (for ARP/RARP/BOOTP/DHCP) and unicast. */
RTL_W8(ChipCmd,CmdRxEnb | CmdTxEnb);
/* Disable all known interrupts by setting the interrupt mask. */
RTL_W16(IntrMask,0);
RTL_W16(IntrMask,rtl8139_intr_mask);
/* Clear watchdog timer */
nic->timeout = 0;
}
static int rtl_transmit(struct nic *nic, char *data,int len)
{
/* Mask the bit that says "this is an io addr" */
ioaddr = nic->ioaddr;
debug_print("rtl_transmit() \r\n");
/* Wait ... */
while(nic->timeout > 0)
;
memcpy(tx_buffer ,data, len);
/* Note: RTL8139 doesn't auto-pad, send minimum payload (another 4
* bytes are sent automatically for the FCS, totalling to 64 bytes). */
while (len < ETH_ZLEN) {
tx_buffer[len++] = '\0';
}
RTL_W32(TxAddr0 + cur_tx*4,(unsigned long)tx_buffer);
RTL_W32(TxStatus0 + cur_tx*4,((TX_FIFO_THRESH<<11) & 0x003f0000) | len);
/* Set a timer just in case we never hear from the board again . */
nic->timeout = RTL_TIMEOUT;
return len;
}
int
rtl_ioctl(struct nic *nic,u_long cmd,caddr_t data)
{
/* Mask the bit that says "this is an io addr" */
ioaddr = nic->ioaddr;
return 0;
}
/*
* $Log: rtl8139.c,v $
* Revision 1.10 2002/02/21 08:25:00 linfusheng
* update
*
* Revision 1.9 2002/02/07 10:25:35 linfusheng
* update
*
* Revision 1.8 2002/02/07 01:08:53 linfusheng
* update
*
* Revision 1.7 2002/02/06 07:59:04 linfusheng
* update
*
* Revision 1.6 2002/02/06 07:42:18 linfusheng
* update
*
* Revision 1.5 2002/02/06 07:28:51 linfusheng
* update
*
* Revision 1.4 2002/02/06 02:16:25 linfusheng
* update
*
* Revision 1.3 2002/01/28 01:13:52 linfusheng
* update
*
* Revision 1.2 2002/01/28 00:46:25 linfusheng
* update
*
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -