📄 复件 rtl8139.c
字号:
/*
* $Id: rtl8139.c,v 1.10 2002/02/21 08:25:00 linfusheng Exp $
*/
#include "includes.h"
#include "ether.h"
#include "nic.h"
#include "pci.h"
#include "pci_ids.h"
#include "ucos_timer.h"
#include "interrupt.h"
#define RTL_TIMEOUT (6)
//#define USE_IO_OPS
#ifdef USE_IO_OPS
#define RTL_R8(reg) UCOS_INB (((unsigned long)ioaddr) + (reg))
#define RTL_R16(reg) UCOS_INW (((unsigned long)ioaddr) + (reg))
#define RTL_R32(reg) ((unsigned long) UCOS_IND (((unsigned long)ioaddr) + (reg)))
#define RTL_W8(reg, val8) UCOS_OUTB ((val8), ((unsigned long)ioaddr) + (reg))
#define RTL_W16(reg, val16) UCOS_OUTW ((val16), ((unsigned long)ioaddr) + (reg))
#define RTL_W32(reg, val32) UCOS_OUTD ((val32), ((unsigned long)ioaddr) + (reg))
#define RTL_W8_F RTL_W8
#define RTL_W16_F RTL_W16
#define RTL_W32_F RTL_W32
#else
#define RTL_R8(reg) readb(((unsigned long)ioaddr) + (reg))
#define RTL_R16(reg) readw(((unsigned long)ioaddr) + (reg))
#define RTL_R32(reg) ((unsigned long) readl (((unsigned long)ioaddr) + (reg)))
#define RTL_W8(reg, val8) writeb ((val8), ((unsigned long)ioaddr) + (reg))
#define RTL_W16(reg, val16) writew ((val16), ((unsigned long)ioaddr) + (reg))
#define RTL_W32(reg, val32) writel ((val32), ((unsigned long)ioaddr) + (reg))
#define RTL_W8_F RTL_W8
#define RTL_W16_F RTL_W16
#define RTL_W32_F RTL_W32
#endif
#undef DEBUG_RTL8139
//#define DEBUG_RTL8139
/* Symbolic offsets to registers. */
enum RTL8139_registers {
MAC0=0, /* Ethernet hardware address. */
MAR0=8, /* Multicast filter. */
TxStatus0=0x10, /* Transmit status (four 32bit registers). */
TxAddr0=0x20, /* Tx descriptors (also four 32bit). */
RxBuf=0x30, RxEarlyCnt=0x34, RxEarlyStatus=0x36,
ChipCmd=0x37, RxBufPtr=0x38, RxBufAddr=0x3A,
IntrMask=0x3C, IntrStatus=0x3E,
TxConfig=0x40, RxConfig=0x44,
Timer=0x48, /* general-purpose counter. */
RxMissed=0x4C, /* 24 bits valid, write clears. */
Cfg9346=0x50, Config0=0x51, Config1=0x52,
TimerIntrReg=0x54, /* intr if gp counter reaches this value */
MediaStatus=0x58,
Config3=0x59,
MultiIntr=0x5C,
RevisionID=0x5E, /* revision of the RTL8139 chip */
TxSummary=0x60,
MII_BMCR=0x62, MII_BMSR=0x64, NWayAdvert=0x66, NWayLPAR=0x68,
NWayExpansion=0x6A,
DisconnectCnt=0x6C, FalseCarrierCnt=0x6E,
NWayTestReg=0x70,
RxCnt=0x72, /* packet received counter */
CSCR=0x74, /* chip status and configuration register */
PhyParm1=0x78,TwisterParm=0x7c,PhyParm2=0x80, /* undocumented */
/* from 0x84 onwards are a number of power management/wakeup frame
* definitions we will probably never need to know about. */
};
enum ChipCmdBits {
CmdReset=0x10, CmdRxEnb=0x08, CmdTxEnb=0x04, RxBufEmpty=0x01, };
/* Interrupt register bits, using my own meaningful names. */
enum IntrStatusBits {
PCIErr=0x8000, PCSTimeout=0x4000, CableLenChange= 0x2000,
RxFIFOOver=0x40, RxUnderrun=0x20, RxOverflow=0x10,
TxErr=0x08, TxOK=0x04, RxErr=0x02, RxOK=0x01,
RxAckBits = RxFIFOOver | RxOverflow | RxOK,
};
enum TxStatusBits {
TxHostOwns=0x2000, TxUnderrun=0x4000, TxStatOK=0x8000,
TxOutOfWindow=0x20000000, TxAborted=0x40000000,
TxCarrierLost=0x80000000,
};
enum RxStatusBits {
RxMulticast=0x8000, RxPhysical=0x4000, RxBroadcast=0x2000,
RxBadSymbol=0x0020, RxRunt=0x0010, RxTooLong=0x0008, RxCRCErr=0x0004,
RxBadAlign=0x0002, RxStatusOK=0x0001,
};
enum MediaStatusBits {
MSRTxFlowEnable=0x80, MSRRxFlowEnable=0x40, MSRSpeed10=0x08,
MSRLinkFail=0x04, MSRRxPauseFlag=0x02, MSRTxPauseFlag=0x01,
};
enum MIIBMCRBits {
BMCRReset=0x8000, BMCRSpeed100=0x2000, BMCRNWayEnable=0x1000,
BMCRRestartNWay=0x0200, BMCRDuplex=0x0100,
};
enum CSCRBits {
CSCR_LinkOKBit=0x0400, CSCR_LinkChangeBit=0x0800,
CSCR_LinkStatusBits=0x0f000, CSCR_LinkDownOffCmd=0x003c0,
CSCR_LinkDownCmd=0x0f3c0,
};
/* Bits in RxConfig. */
enum rx_mode_bits {
RxCfgWrap=0x80,
AcceptErr=0x20, AcceptRunt=0x10, AcceptBroadcast=0x08,
AcceptMulticast=0x04, AcceptMyPhys=0x02, AcceptAllPhys=0x01,
};
static const unsigned short rtl8139_intr_mask =
PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver |
TxErr | TxOK | RxErr | RxOK;
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
static int max_interrupt_work = 20;
#define N_RTL8139 4
struct rtl_private_data{
struct nic *nic;
};
/* PCI Tuning Parameters
Threshold is bytes transferred to chip before transmission starts. */
struct rtl_private_data private_datas[N_RTL8139];
static unsigned long ioaddr;
#define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */
#define RX_FIFO_THRESH 4 /* Rx buffer level before first PCI xfer. */
#define RX_DMA_BURST 4 /* Maximum PCI burst, '4' is 256 bytes */
#define TX_DMA_BURST 4 /* Calculate as 16<<val. */
#define NUM_TX_DESC 4 /* Number of Tx descriptor registers. */
#define TX_BUF_SIZE MAX_ETH_FRAME_SIZE /* FCS is added by the chip */
#define RX_BUF_LEN_IDX 0 /* 0, 1, 2 is allowed - 8,16,32K rx buffer */
#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)
static unsigned int cur_rx,cur_tx;
/* The RTL8139 can only transmit from a contiguous, aligned memory block. */
static unsigned char tx_buffer[TX_BUF_SIZE];
static unsigned char rx_ring[RX_BUF_LEN+16];
int read_eeprom(int location);
static void rtl_reset(struct nic* nic);
static int rtl_recv(struct nic *nic,unsigned char *packet,int *packetlen);
static int rtl_transmit(struct nic *nic, char *data,int len);
static int rtl_ioctl(struct nic *nic,u_long cmd,caddr_t data);
/* Serial EEPROM section. */
/* EEPROM_Ctrl bits. */
#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */
#define EE_CS 0x08 /* EEPROM chip select. */
#define EE_DATA_WRITE 0x02 /* EEPROM chip data in. */
#define EE_WRITE_0 0x00
#define EE_WRITE_1 0x02
#define EE_DATA_READ 0x01 /* EEPROM chip data out. */
#define EE_ENB (0x80 | EE_CS)
/*
Delay between EEPROM clock transitions.
No extra delay is needed with 33Mhz PCI, but 66Mhz may change this.
*/
#define eeprom_delay() RTL_R8(Cfg9346)
/* The EEPROM commands include the alway-set leading bit. */
#define EE_WRITE_CMD (5 << 6)
#define EE_READ_CMD (6 << 6)
#define EE_ERASE_CMD (7 << 6)
static int read_eeprom(int location)
{
int i;
unsigned int retval = 0;
long ee_addr = ioaddr + Cfg9346;
int read_cmd = location | EE_READ_CMD;
RTL_W8(Cfg9346,EE_ENB & ~EE_CS);
RTL_W8(Cfg9346,EE_ENB);
/* Shift the read command bits out. */
for (i = 10; i >= 0; i--) {
int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
RTL_W8(Cfg9346,EE_ENB | dataval);
eeprom_delay();
RTL_W8(Cfg9346,EE_ENB | dataval | EE_SHIFT_CLK);
eeprom_delay();
}
RTL_W8(Cfg9346,EE_ENB);
eeprom_delay();
for (i = 16; i > 0; i--) {
RTL_W8(Cfg9346,EE_ENB | EE_SHIFT_CLK);
eeprom_delay();
retval = (retval << 1) | ((RTL_R8(Cfg9346) & EE_DATA_READ) ? 1 : 0);
RTL_W8(Cfg9346,EE_ENB);
eeprom_delay();
}
/* Terminate the EEPROM access. */
RTL_W8(Cfg9346,~EE_CS);
return retval;
}
static void rtl8139_rx_interrupt (struct rtl_private_data *private_data)
{
#ifdef DEBUG_RTL8139
debug_print("enter rx_interrupt process \r\n ! ");
#endif
#ifdef DEBUG_RTL8139
debug_print("In rtl8139_rx(), current %4.4x BufAddr %4.4x,"
" free to %4.4x, Cmd %2.2x.\r\n", cur_rx,
RTL_R16 (RxBufAddr),
RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd));
#endif
while ((RTL_R8 (ChipCmd) & RxBufEmpty) == 0) {
int ring_offset = cur_rx % RX_BUF_LEN;
DWORD rx_status;
unsigned int rx_size;
unsigned int pkt_size;
/* read size+status of next frame from DMA ring buffer */
rx_status = (*(DWORD *) (rx_ring + ring_offset));
rx_size = rx_status >> 16;
pkt_size = rx_size - 4;
#ifdef DEBUG_RTL8139
debug_print ("rtl8139_rx() status %4.4x, size %4.4x,"
" cur %4.4x.\r\n", rx_status,
rx_size, cur_rx);
#endif
/* Packet copy from FIFO still in progress.
* Theoretically, this should never happen
* since EarlyRx is disabled.
*/
if (rx_size == 0xfff0) {
// tp->xstats.early_rx++;
break;
}
/* If Rx err or invalid rx_size/rx_status received
* (which happens if we get lost in the ring),
* Rx process gets reset, so we abort any further
* Rx processing.
*/
if ((rx_size > (MAX_ETH_FRAME_SIZE+4)) ||
(rx_size < 8) ||
(!(rx_status & RxStatusOK))) {
// rtl8139_rx_err (rx_status, dev, tp, ioaddr);
return;
}
/* Malloc up new buffer, compatible with net-2e. */
/* Omit the four octet CRC from the length. */
/* TODO: consider allocating skb's outside of
* interrupt context, both to speed interrupt processing,
* and also to reduce the chances of having to
* drop packets here under memory pressure.
*/
netif_rx(&rx_ring[ring_offset + 4], pkt_size,private_data->nic);
cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
RTL_W16 (RxBufPtr, cur_rx - 16);
if (RTL_R16 (IntrStatus) & RxAckBits)
RTL_W16_F (IntrStatus, RxAckBits);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -