📄 via-rhine.c
字号:
/* Ethernet address filter type */#define PKT_TYPE_DIRECTED 0x0001 /* obsolete, directed address is always accepted */#define PKT_TYPE_MULTICAST 0x0002#define PKT_TYPE_ALL_MULTICAST 0x0004#define PKT_TYPE_BROADCAST 0x0008#define PKT_TYPE_PROMISCUOUS 0x0020#define PKT_TYPE_LONG 0x2000#define PKT_TYPE_RUNT 0x4000#define PKT_TYPE_ERROR 0x8000 /* accept error packets, e.g. CRC error *//* Loopback mode */#define NIC_LB_NONE 0x00#define NIC_LB_INTERNAL 0x01#define NIC_LB_PHY 0x02 /* MII or Internal-10BaseT loopback */#define TX_RING_SIZE 2#define RX_RING_SIZE 2#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. *//* Transmit and receive descriptors definition */struct rhine_tx_desc{ union VTC_tx_status_tag { struct { unsigned long ncro:1; unsigned long ncr1:1; unsigned long ncr2:1; unsigned long ncr3:1; unsigned long cols:1; unsigned long reserve_1:2; unsigned long cdh:1; unsigned long abt:1; unsigned long owc:1; unsigned long crs:1; unsigned long udf:1; unsigned long tbuff:1; unsigned long serr:1; unsigned long jab:1; unsigned long terr:1; unsigned long reserve_2:15; unsigned long own_bit:1; } bits; unsigned long lw; } tx_status; union VTC_tx_ctrl_tag { struct { unsigned long tx_buf_size:11; unsigned long extend_tx_buf_size:4; unsigned long chn:1; unsigned long crc:1; unsigned long reserve_1:4; unsigned long stp:1; unsigned long edp:1; unsigned long ic:1; unsigned long reserve_2:8; } bits; unsigned long lw; } tx_ctrl; unsigned long buf_addr_1:32; unsigned long buf_addr_2:32;};struct rhine_rx_desc{ union VTC_rx_status_tag { struct { unsigned long rerr:1; unsigned long crc_error:1; unsigned long fae:1; unsigned long fov:1; unsigned long toolong:1; unsigned long runt:1; unsigned long serr:1; unsigned long buff:1; unsigned long edp:1; unsigned long stp:1; unsigned long chn:1; unsigned long phy:1; unsigned long bar:1; unsigned long mar:1; unsigned long reserve_1:1; unsigned long rxok:1; unsigned long frame_length:11; unsigned long reverve_2:4; unsigned long own_bit:1; } bits; unsigned long lw; } rx_status; union VTC_rx_ctrl_tag { struct { unsigned long rx_buf_size:11; unsigned long extend_rx_buf_size:4; unsigned long reserved_1:17; } bits; unsigned long lw; } rx_ctrl; unsigned long buf_addr_1:32; unsigned long buf_addr_2:32;};/* The I/O extent. */#define rhine_TOTAL_SIZE 0x80#ifdef HAVE_DEVLISTstruct netdev_entry rhine_drv = { "rhine", rhine_probe, rhine_TOTAL_SIZE, NULL };#endifstatic int rhine_debug = 1;/* Theory of OperationI. Board CompatibilityThis driver is designed for the VIA 86c100A Rhine-II PCI Fast Ethernetcontroller.II. Board-specific settingsBoards with this chip are functional only in a bus-master PCI slot.Many operational settings are loaded from the EEPROM to the Config word atoffset 0x78. This driver assumes that they are correct.If this driver is compiled to use PCI memory space operations the EEPROMmust be configured to enable memory ops.III. Driver operationIIIa. Ring buffersThis driver uses two statically allocated fixed-size descriptor listsformed into rings by a branch from the final descriptor to the beginning ofthe list. The ring sizes are set at compile time by RX/TX_RING_SIZE.IIIb/c. Transmit/Receive StructureThis driver attempts to use a zero-copy receive and transmit scheme.Alas, all data buffers are required to start on a 32 bit boundary, sothe driver must often copy transmit packets into bounce buffers.The driver allocates full frame size skbuffs for the Rx ring buffers atopen() time and passes the skb->data field to the chip as receive databuffers. When an incoming frame is less than RX_COPYBREAK bytes long,a fresh skbuff is allocated and the frame is copied to the new skbuff.When the incoming frame is larger, the skbuff is passed directly up theprotocol stack. Buffers consumed this way are replaced by newly allocatedskbuffs in the last phase of netdev_rx().The RX_COPYBREAK value is chosen to trade-off the memory wasted byusing a full-sized skbuff for small frames vs. the copying costs of largerframes. New boards are typically used in generously configured machinesand the underfilled buffers have negligible impact compared to the benefit ofa single allocation size, so the default value of zero results in nevercopying packets. When copying is done, the cost is usually mitigated by usinga combined copy/checksum routine. Copying also preloads the cache, which ismost useful with small frames.Since the VIA chips are only able to transfer data to buffers on 32 bitboundaries, the the IP header at offset 14 in an ethernet frame isn'tlongword aligned for further processing. Copying these unaligned buffershas the beneficial effect of 16-byte aligning the IP header.IIId. SynchronizationThe driver runs as two independent, single-threaded flows of control. Oneis the send-packet routine, which enforces single-threaded use by thedev->tbusy flag. The other thread is the interrupt handler, which is singlethreaded by the hardware and interrupt handling software.The send packet thread has partial control over the Tx ring and 'dev->tbusy'flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the nextqueue slot is empty, it clears the tbusy flag when finished otherwise it setsthe 'lp->tx_full' flag.The interrupt handler has exclusive control over the Rx ring and records statsfrom the Tx ring. After reaping the stats, it marks the Tx queue entry asempty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, itclears both the tx_full and tbusy flags.IV. NotesIVb. ReferencesPreliminary VT86C100A manual from http://www.via.com.tw/http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.htmlhttp://cesdis.gsfc.nasa.gov/linux/misc/NWay.htmlIVc. ErrataThe VT86C100A manual is not reliable information.The chip does not handle unaligned transmit or receive buffers, resultingin significant performance degradation for bounce buffer copies on transmitand unaligned IP headers on receive.The chip does not pad to minimum transmit length.*/#define PCI_VENDOR_ID_FET 0x1106#define PCI_DEVICE_ID_FET_3043 0x3043/* The rest of these values should never change. */#define NUM_TX_DESC 2 /* Number of Tx descriptor registers. */static struct rhine_private{ char devname[8]; /* Used only for kernel debugging. */ const char *product_name; struct rhine_rx_desc *rx_ring; struct rhine_tx_desc *tx_ring; char *rx_buffs[RX_RING_SIZE]; char *tx_buffs[TX_RING_SIZE]; /* temporary Rx buffers. */ int chip_id; int chip_revision; unsigned short ioaddr; unsigned int cur_rx, cur_tx; /* The next free and used entries */ unsigned int dirty_rx, dirty_tx; /* The saved address of a sent-in-place packet/buffer, for skfree(). */ struct sk_buff *tx_skbuff[TX_RING_SIZE]; unsigned char mc_filter[8]; /* Current multicast filter. */ char phys[4]; /* MII device addresses. */ unsigned int tx_full:1; /* The Tx queue is full. */ unsigned int full_duplex:1; /* Full-duplex operation requested. */ unsigned int default_port:4; /* Last dev->if_port value. */ unsigned int media2:4; /* Secondary monitored media port. */ unsigned int medialock:1; /* Don't sense media type. */ unsigned int mediasense:1; /* Media sensing in progress. */}rhine;static struct nic *rhine_probe1 (struct nic *dev, int ioaddr, int chip_id, int options);static int QueryAuto (int);static int ReadMII (int byMIIIndex, int);static void WriteMII (char, char, char, int);static void MIIDelay (void);static void rhine_init_ring (struct nic *dev);static void rhine_disable (struct nic *nic);static void rhine_reset (struct nic *nic);static int rhine_poll (struct nic *nic);static void rhine_transmit (struct nic *nic, const char *d, unsigned int t, unsigned int s, const char *p);/* Linux support functions */#define virt_to_bus(x) ((unsigned long)x)#define bus_to_virt(x) ((void *)x)/* Initialize the Rx and Tx rings, along with various 'dev' bits. */static voidrhine_init_ring (struct nic *nic){ struct rhine_private *tp = (struct rhine_private *) nic->priv_data; int i; tp->tx_full = 0; tp->cur_rx = tp->cur_tx = 0; tp->dirty_rx = tp->dirty_tx = 0; for (i = 0; i < RX_RING_SIZE; i++) { tp->rx_ring[i].rx_status.bits.own_bit = 1; tp->rx_ring[i].rx_ctrl.bits.rx_buf_size = 1536; tp->rx_ring[i].buf_addr_1 = virt_to_bus (tp->rx_buffs[i]); tp->rx_ring[i].buf_addr_2 = virt_to_bus (&tp->rx_ring[i + 1]); /* printf("[%d]buf1=%hX,buf2=%hX",i,tp->rx_ring[i].buf_addr_1,tp->rx_ring[i].buf_addr_2); */ } /* Mark the last entry as wrapping the ring. */ /* tp->rx_ring[i-1].rx_ctrl.bits.rx_buf_size =1518; */ tp->rx_ring[i - 1].buf_addr_2 = virt_to_bus (&tp->rx_ring[0]); /*printf("[%d]buf1=%hX,buf2=%hX",i-1,tp->rx_ring[i-1].buf_addr_1,tp->rx_ring[i-1].buf_addr_2); */ /* The Tx buffer descriptor is filled in as needed, but we do need to clear the ownership bit. */ for (i = 0; i < TX_RING_SIZE; i++) { tp->tx_ring[i].tx_status.lw = 0; tp->tx_ring[i].tx_ctrl.lw = 0x00e08000; tp->tx_ring[i].buf_addr_1 = virt_to_bus (tp->tx_buffs[i]); tp->tx_ring[i].buf_addr_2 = virt_to_bus (&tp->tx_ring[i + 1]); /* printf("[%d]buf1=%hX,buf2=%hX",i,tp->tx_ring[i].buf_addr_1,tp->tx_ring[i].buf_addr_2); */ } tp->tx_ring[i - 1].buf_addr_2 = virt_to_bus (&tp->tx_ring[0]); /* printf("[%d]buf1=%hX,buf2=%hX",i,tp->tx_ring[i-1].buf_addr_1,tp->tx_ring[i-1].buf_addr_2); */}intQueryAuto (int ioaddr){ int byMIIIndex; int MIIReturn; int advertising,mii_reg5; int negociated; byMIIIndex = 0x04; MIIReturn = ReadMII (byMIIIndex, ioaddr); advertising=MIIReturn; byMIIIndex = 0x05; MIIReturn = ReadMII (byMIIIndex, ioaddr); mii_reg5=MIIReturn; negociated=mii_reg5 & advertising; if ( (negociated & 0x100) || (negociated & 0x1C0) == 0x40 ) return 1; else return 0;}intReadMII (int byMIIIndex, int ioaddr){ int ReturnMII; char byMIIAdrbak; char byMIICRbak; char byMIItemp; byMIIAdrbak = inb (byMIIAD); byMIICRbak = inb (byMIICR); outb (byMIICRbak & 0x7f, byMIICR); MIIDelay (); outb (byMIIIndex, byMIIAD); MIIDelay (); outb (inb (byMIICR) | 0x40, byMIICR); byMIItemp = inb (byMIICR); byMIItemp = byMIItemp & 0x40; while (byMIItemp != 0) { byMIItemp = inb (byMIICR); byMIItemp = byMIItemp & 0x40; } MIIDelay (); ReturnMII = inw (wMIIDATA); outb (byMIIAdrbak, byMIIAD); outb (byMIICRbak, byMIICR); MIIDelay (); return (ReturnMII);}voidWriteMII (char byMIISetByte, char byMIISetBit, char byMIIOP, int ioaddr){ int ReadMIItmp; int MIIMask; char byMIIAdrbak; char byMIICRbak; char byMIItemp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -