17c478bd9Sstevel@tonic-gate /* rhine.c:Fast Ethernet driver for Linux. */
27c478bd9Sstevel@tonic-gate /*
37c478bd9Sstevel@tonic-gate 	Adapted 09-jan-2000 by Paolo Marini (paolom@prisma-eng.it)
47c478bd9Sstevel@tonic-gate 
57c478bd9Sstevel@tonic-gate         originally written by Donald Becker.
67c478bd9Sstevel@tonic-gate 
77c478bd9Sstevel@tonic-gate 	This software may be used and distributed according to the terms
87c478bd9Sstevel@tonic-gate 	of the GNU Public License (GPL), incorporated herein by reference.
97c478bd9Sstevel@tonic-gate 	Drivers derived from this code also fall under the GPL and must retain
107c478bd9Sstevel@tonic-gate 	this authorship and copyright notice.
117c478bd9Sstevel@tonic-gate 
127c478bd9Sstevel@tonic-gate 	Under no circumstances are the authors responsible for
137c478bd9Sstevel@tonic-gate 	the proper functioning of this software, nor do the authors assume any
147c478bd9Sstevel@tonic-gate 	responsibility for damages incurred with its use.
157c478bd9Sstevel@tonic-gate 
167c478bd9Sstevel@tonic-gate 	This driver is designed for the VIA VT86C100A Rhine-II PCI Fast Ethernet
177c478bd9Sstevel@tonic-gate 	controller.
187c478bd9Sstevel@tonic-gate 
197c478bd9Sstevel@tonic-gate */
207c478bd9Sstevel@tonic-gate 
217c478bd9Sstevel@tonic-gate static const char *version = "rhine.c v1.0.1 2003-02-06\n";
227c478bd9Sstevel@tonic-gate 
237c478bd9Sstevel@tonic-gate /* A few user-configurable values. */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate /* Size of the in-memory receive ring. */
267c478bd9Sstevel@tonic-gate #define RX_BUF_LEN_IDX	3	/* 0==8K, 1==16K, 2==32K, 3==64K */
277c478bd9Sstevel@tonic-gate #define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
307c478bd9Sstevel@tonic-gate #define TX_BUF_SIZE	1536
317c478bd9Sstevel@tonic-gate #define RX_BUF_SIZE	1536
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate /* PCI Tuning Parameters
347c478bd9Sstevel@tonic-gate    Threshold is bytes transferred to chip before transmission starts. */
357c478bd9Sstevel@tonic-gate #define TX_FIFO_THRESH 256	/* In bytes, rounded down to 32 byte units. */
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate /* The following settings are log_2(bytes)-4:  0 == 16 bytes .. 6==1024. */
387c478bd9Sstevel@tonic-gate #define RX_FIFO_THRESH	4	/* Rx buffer level before first PCI xfer.  */
397c478bd9Sstevel@tonic-gate #define RX_DMA_BURST	4	/* Maximum PCI burst, '4' is 256 bytes */
407c478bd9Sstevel@tonic-gate #define TX_DMA_BURST	4
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate /* Operational parameters that usually are not changed. */
437c478bd9Sstevel@tonic-gate /* Time in jiffies before concluding the transmitter is hung. */
447c478bd9Sstevel@tonic-gate #define TX_TIMEOUT  ((2000*HZ)/1000)
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #include "etherboot.h"
477c478bd9Sstevel@tonic-gate #include "nic.h"
487c478bd9Sstevel@tonic-gate #include "pci.h"
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate /* define all ioaddr */
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate #define byPAR0				ioaddr
537c478bd9Sstevel@tonic-gate #define byRCR				ioaddr + 6
547c478bd9Sstevel@tonic-gate #define byTCR				ioaddr + 7
557c478bd9Sstevel@tonic-gate #define byCR0				ioaddr + 8
567c478bd9Sstevel@tonic-gate #define byCR1				ioaddr + 9
577c478bd9Sstevel@tonic-gate #define byISR0				ioaddr + 0x0c
587c478bd9Sstevel@tonic-gate #define byISR1				ioaddr + 0x0d
597c478bd9Sstevel@tonic-gate #define byIMR0				ioaddr + 0x0e
607c478bd9Sstevel@tonic-gate #define byIMR1				ioaddr + 0x0f
617c478bd9Sstevel@tonic-gate #define byMAR0				ioaddr + 0x10
627c478bd9Sstevel@tonic-gate #define byMAR1				ioaddr + 0x11
637c478bd9Sstevel@tonic-gate #define byMAR2				ioaddr + 0x12
647c478bd9Sstevel@tonic-gate #define byMAR3				ioaddr + 0x13
657c478bd9Sstevel@tonic-gate #define byMAR4				ioaddr + 0x14
667c478bd9Sstevel@tonic-gate #define byMAR5				ioaddr + 0x15
677c478bd9Sstevel@tonic-gate #define byMAR6				ioaddr + 0x16
687c478bd9Sstevel@tonic-gate #define byMAR7				ioaddr + 0x17
697c478bd9Sstevel@tonic-gate #define dwCurrentRxDescAddr		ioaddr + 0x18
707c478bd9Sstevel@tonic-gate #define dwCurrentTxDescAddr		ioaddr + 0x1c
717c478bd9Sstevel@tonic-gate #define dwCurrentRDSE0			ioaddr + 0x20
727c478bd9Sstevel@tonic-gate #define dwCurrentRDSE1			ioaddr + 0x24
737c478bd9Sstevel@tonic-gate #define dwCurrentRDSE2			ioaddr + 0x28
747c478bd9Sstevel@tonic-gate #define dwCurrentRDSE3			ioaddr + 0x2c
757c478bd9Sstevel@tonic-gate #define dwNextRDSE0			ioaddr + 0x30
767c478bd9Sstevel@tonic-gate #define dwNextRDSE1			ioaddr + 0x34
777c478bd9Sstevel@tonic-gate #define dwNextRDSE2			ioaddr + 0x38
787c478bd9Sstevel@tonic-gate #define dwNextRDSE3			ioaddr + 0x3c
797c478bd9Sstevel@tonic-gate #define dwCurrentTDSE0			ioaddr + 0x40
807c478bd9Sstevel@tonic-gate #define dwCurrentTDSE1			ioaddr + 0x44
817c478bd9Sstevel@tonic-gate #define dwCurrentTDSE2			ioaddr + 0x48
827c478bd9Sstevel@tonic-gate #define dwCurrentTDSE3			ioaddr + 0x4c
837c478bd9Sstevel@tonic-gate #define dwNextTDSE0			ioaddr + 0x50
847c478bd9Sstevel@tonic-gate #define dwNextTDSE1			ioaddr + 0x54
857c478bd9Sstevel@tonic-gate #define dwNextTDSE2			ioaddr + 0x58
867c478bd9Sstevel@tonic-gate #define dwNextTDSE3			ioaddr + 0x5c
877c478bd9Sstevel@tonic-gate #define dwCurrRxDMAPtr			ioaddr + 0x60
887c478bd9Sstevel@tonic-gate #define dwCurrTxDMAPtr			ioaddr + 0x64
897c478bd9Sstevel@tonic-gate #define byMPHY				ioaddr + 0x6c
907c478bd9Sstevel@tonic-gate #define byMIISR				ioaddr + 0x6d
917c478bd9Sstevel@tonic-gate #define byBCR0				ioaddr + 0x6e
927c478bd9Sstevel@tonic-gate #define byBCR1				ioaddr + 0x6f
937c478bd9Sstevel@tonic-gate #define byMIICR				ioaddr + 0x70
947c478bd9Sstevel@tonic-gate #define byMIIAD				ioaddr + 0x71
957c478bd9Sstevel@tonic-gate #define wMIIDATA			ioaddr + 0x72
967c478bd9Sstevel@tonic-gate #define byEECSR				ioaddr + 0x74
977c478bd9Sstevel@tonic-gate #define byTEST				ioaddr + 0x75
987c478bd9Sstevel@tonic-gate #define byGPIO				ioaddr + 0x76
997c478bd9Sstevel@tonic-gate #define byCFGA				ioaddr + 0x78
1007c478bd9Sstevel@tonic-gate #define byCFGB				ioaddr + 0x79
1017c478bd9Sstevel@tonic-gate #define byCFGC				ioaddr + 0x7a
1027c478bd9Sstevel@tonic-gate #define byCFGD				ioaddr + 0x7b
1037c478bd9Sstevel@tonic-gate #define wTallyCntMPA			ioaddr + 0x7c
1047c478bd9Sstevel@tonic-gate #define wTallyCntCRC			ioaddr + 0x7d
1057c478bd9Sstevel@tonic-gate #define bySTICKHW			ioaddr + 0x83
1067c478bd9Sstevel@tonic-gate #define byWOLcrClr			ioaddr + 0xA4
1077c478bd9Sstevel@tonic-gate #define byWOLcgClr			ioaddr + 0xA7
1087c478bd9Sstevel@tonic-gate #define byPwrcsrClr			ioaddr + 0xAC
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate /*---------------------  Exioaddr Definitions -------------------------*/
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate /*
1137c478bd9Sstevel@tonic-gate  * Bits in the RCR register
1147c478bd9Sstevel@tonic-gate  */
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate #define RCR_RRFT2		0x80
1177c478bd9Sstevel@tonic-gate #define RCR_RRFT1		0x40
1187c478bd9Sstevel@tonic-gate #define RCR_RRFT0		0x20
1197c478bd9Sstevel@tonic-gate #define RCR_PROM		0x10
1207c478bd9Sstevel@tonic-gate #define RCR_AB			0x08
1217c478bd9Sstevel@tonic-gate #define RCR_AM			0x04
1227c478bd9Sstevel@tonic-gate #define RCR_AR			0x02
1237c478bd9Sstevel@tonic-gate #define RCR_SEP			0x01
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate /*
1267c478bd9Sstevel@tonic-gate  * Bits in the TCR register
1277c478bd9Sstevel@tonic-gate  */
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate #define TCR_RTSF		0x80
1307c478bd9Sstevel@tonic-gate #define TCR_RTFT1		0x40
1317c478bd9Sstevel@tonic-gate #define TCR_RTFT0		0x20
1327c478bd9Sstevel@tonic-gate #define TCR_OFSET		0x08
1337c478bd9Sstevel@tonic-gate #define TCR_LB1			0x04	/* loopback[1] */
1347c478bd9Sstevel@tonic-gate #define TCR_LB0			0x02	/* loopback[0] */
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate /*
1377c478bd9Sstevel@tonic-gate  * Bits in the CR0 register
1387c478bd9Sstevel@tonic-gate  */
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate #define CR0_RDMD		0x40	/* rx descriptor polling demand */
1417c478bd9Sstevel@tonic-gate #define CR0_TDMD		0x20	/* tx descriptor polling demand */
1427c478bd9Sstevel@tonic-gate #define CR0_TXON		0x10
1437c478bd9Sstevel@tonic-gate #define CR0_RXON		0x08
1447c478bd9Sstevel@tonic-gate #define CR0_STOP		0x04	/* stop NIC, default = 1 */
1457c478bd9Sstevel@tonic-gate #define CR0_STRT		0x02	/* start NIC */
1467c478bd9Sstevel@tonic-gate #define CR0_INIT		0x01	/* start init process */
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate /*
1507c478bd9Sstevel@tonic-gate  * Bits in the CR1 register
1517c478bd9Sstevel@tonic-gate  */
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate #define CR1_SFRST		0x80	/* software reset */
1547c478bd9Sstevel@tonic-gate #define CR1_RDMD1		0x40	/* RDMD1 */
1557c478bd9Sstevel@tonic-gate #define CR1_TDMD1		0x20	/* TDMD1 */
1567c478bd9Sstevel@tonic-gate #define CR1_KEYPAG		0x10	/* turn on par/key */
1577c478bd9Sstevel@tonic-gate #define CR1_DPOLL		0x08	/* disable rx/tx auto polling */
1587c478bd9Sstevel@tonic-gate #define CR1_FDX			0x04	/* full duplex mode */
1597c478bd9Sstevel@tonic-gate #define CR1_ETEN		0x02	/* early tx mode */
1607c478bd9Sstevel@tonic-gate #define CR1_EREN		0x01	/* early rx mode */
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate /*
1637c478bd9Sstevel@tonic-gate  * Bits in the CR register
1647c478bd9Sstevel@tonic-gate  */
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate #define CR_RDMD			0x0040	/* rx descriptor polling demand */
1677c478bd9Sstevel@tonic-gate #define CR_TDMD			0x0020	/* tx descriptor polling demand */
1687c478bd9Sstevel@tonic-gate #define CR_TXON			0x0010
1697c478bd9Sstevel@tonic-gate #define CR_RXON			0x0008
1707c478bd9Sstevel@tonic-gate #define CR_STOP			0x0004	/* stop NIC, default = 1 */
1717c478bd9Sstevel@tonic-gate #define CR_STRT			0x0002	/* start NIC */
1727c478bd9Sstevel@tonic-gate #define CR_INIT			0x0001	/* start init process */
1737c478bd9Sstevel@tonic-gate #define CR_SFRST		0x8000	/* software reset */
1747c478bd9Sstevel@tonic-gate #define CR_RDMD1		0x4000	/* RDMD1 */
1757c478bd9Sstevel@tonic-gate #define CR_TDMD1		0x2000	/* TDMD1 */
1767c478bd9Sstevel@tonic-gate #define CR_KEYPAG		0x1000	/* turn on par/key */
1777c478bd9Sstevel@tonic-gate #define CR_DPOLL		0x0800	/* disable rx/tx auto polling */
1787c478bd9Sstevel@tonic-gate #define CR_FDX			0x0400	/* full duplex mode */
1797c478bd9Sstevel@tonic-gate #define CR_ETEN			0x0200	/* early tx mode */
1807c478bd9Sstevel@tonic-gate #define CR_EREN			0x0100	/* early rx mode */
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate /*
1837c478bd9Sstevel@tonic-gate  * Bits in the IMR0 register
1847c478bd9Sstevel@tonic-gate  */
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate #define IMR0_CNTM		0x80
1877c478bd9Sstevel@tonic-gate #define IMR0_BEM		0x40
1887c478bd9Sstevel@tonic-gate #define IMR0_RUM		0x20
1897c478bd9Sstevel@tonic-gate #define IMR0_TUM		0x10
1907c478bd9Sstevel@tonic-gate #define IMR0_TXEM		0x08
1917c478bd9Sstevel@tonic-gate #define IMR0_RXEM		0x04
1927c478bd9Sstevel@tonic-gate #define IMR0_PTXM		0x02
1937c478bd9Sstevel@tonic-gate #define IMR0_PRXM		0x01
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate /* define imrshadow */
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate #define IMRShadow		0x5AFF
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate /*
2007c478bd9Sstevel@tonic-gate  * Bits in the IMR1 register
2017c478bd9Sstevel@tonic-gate  */
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate #define IMR1_INITM		0x80
2047c478bd9Sstevel@tonic-gate #define IMR1_SRCM		0x40
2057c478bd9Sstevel@tonic-gate #define IMR1_NBFM		0x10
2067c478bd9Sstevel@tonic-gate #define IMR1_PRAIM		0x08
2077c478bd9Sstevel@tonic-gate #define IMR1_RES0M		0x04
2087c478bd9Sstevel@tonic-gate #define IMR1_ETM		0x02
2097c478bd9Sstevel@tonic-gate #define IMR1_ERM		0x01
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate /*
2127c478bd9Sstevel@tonic-gate  * Bits in the ISR register
2137c478bd9Sstevel@tonic-gate  */
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate #define ISR_INITI		0x8000
2167c478bd9Sstevel@tonic-gate #define ISR_SRCI		0x4000
2177c478bd9Sstevel@tonic-gate #define ISR_ABTI		0x2000
2187c478bd9Sstevel@tonic-gate #define ISR_NORBF		0x1000
2197c478bd9Sstevel@tonic-gate #define ISR_PKTRA		0x0800
2207c478bd9Sstevel@tonic-gate #define ISR_RES0		0x0400
2217c478bd9Sstevel@tonic-gate #define ISR_ETI			0x0200
2227c478bd9Sstevel@tonic-gate #define ISR_ERI			0x0100
2237c478bd9Sstevel@tonic-gate #define ISR_CNT			0x0080
2247c478bd9Sstevel@tonic-gate #define ISR_BE			0x0040
2257c478bd9Sstevel@tonic-gate #define ISR_RU			0x0020
2267c478bd9Sstevel@tonic-gate #define ISR_TU			0x0010
2277c478bd9Sstevel@tonic-gate #define ISR_TXE			0x0008
2287c478bd9Sstevel@tonic-gate #define ISR_RXE			0x0004
2297c478bd9Sstevel@tonic-gate #define ISR_PTX			0x0002
2307c478bd9Sstevel@tonic-gate #define ISR_PRX			0x0001
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate /*
2337c478bd9Sstevel@tonic-gate  * Bits in the ISR0 register
2347c478bd9Sstevel@tonic-gate  */
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate #define ISR0_CNT		0x80
2377c478bd9Sstevel@tonic-gate #define ISR0_BE			0x40
2387c478bd9Sstevel@tonic-gate #define ISR0_RU			0x20
2397c478bd9Sstevel@tonic-gate #define ISR0_TU			0x10
2407c478bd9Sstevel@tonic-gate #define ISR0_TXE		0x08
2417c478bd9Sstevel@tonic-gate #define ISR0_RXE		0x04
2427c478bd9Sstevel@tonic-gate #define ISR0_PTX		0x02
2437c478bd9Sstevel@tonic-gate #define ISR0_PRX		0x01
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate /*
2467c478bd9Sstevel@tonic-gate  * Bits in the ISR1 register
2477c478bd9Sstevel@tonic-gate  */
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate #define ISR1_INITI		0x80
2507c478bd9Sstevel@tonic-gate #define ISR1_SRCI		0x40
2517c478bd9Sstevel@tonic-gate #define ISR1_NORBF		0x10
2527c478bd9Sstevel@tonic-gate #define ISR1_PKTRA		0x08
2537c478bd9Sstevel@tonic-gate #define ISR1_ETI		0x02
2547c478bd9Sstevel@tonic-gate #define ISR1_ERI		0x01
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate /* ISR ABNORMAL CONDITION */
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate #define ISR_ABNORMAL ISR_BE+ISR_RU+ISR_TU+ISR_CNT+ISR_NORBF+ISR_PKTRA
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate /*
2617c478bd9Sstevel@tonic-gate  * Bits in the MIISR register
2627c478bd9Sstevel@tonic-gate  */
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate #define MIISR_MIIERR		0x08
2657c478bd9Sstevel@tonic-gate #define MIISR_MRERR		0x04
2667c478bd9Sstevel@tonic-gate #define MIISR_LNKFL		0x02
2677c478bd9Sstevel@tonic-gate #define MIISR_SPEED		0x01
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate /*
2707c478bd9Sstevel@tonic-gate  * Bits in the MIICR register
2717c478bd9Sstevel@tonic-gate  */
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate #define MIICR_MAUTO		0x80
2747c478bd9Sstevel@tonic-gate #define MIICR_RCMD		0x40
2757c478bd9Sstevel@tonic-gate #define MIICR_WCMD		0x20
2767c478bd9Sstevel@tonic-gate #define MIICR_MDPM		0x10
2777c478bd9Sstevel@tonic-gate #define MIICR_MOUT		0x08
2787c478bd9Sstevel@tonic-gate #define MIICR_MDO		0x04
2797c478bd9Sstevel@tonic-gate #define MIICR_MDI		0x02
2807c478bd9Sstevel@tonic-gate #define MIICR_MDC		0x01
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate /*
2837c478bd9Sstevel@tonic-gate  * Bits in the EECSR register
2847c478bd9Sstevel@tonic-gate  */
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate #define EECSR_EEPR		0x80	/* eeprom programed status, 73h means programed */
2877c478bd9Sstevel@tonic-gate #define EECSR_EMBP		0x40	/* eeprom embeded programming */
2887c478bd9Sstevel@tonic-gate #define EECSR_AUTOLD		0x20	/* eeprom content reload */
2897c478bd9Sstevel@tonic-gate #define EECSR_DPM		0x10	/* eeprom direct programming */
2907c478bd9Sstevel@tonic-gate #define EECSR_CS		0x08	/* eeprom CS pin */
2917c478bd9Sstevel@tonic-gate #define EECSR_SK		0x04	/* eeprom SK pin */
2927c478bd9Sstevel@tonic-gate #define EECSR_DI		0x02	/* eeprom DI pin */
2937c478bd9Sstevel@tonic-gate #define EECSR_DO		0x01	/* eeprom DO pin */
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate /*
2967c478bd9Sstevel@tonic-gate  * Bits in the BCR0 register
2977c478bd9Sstevel@tonic-gate  */
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate #define BCR0_CRFT2		0x20
3007c478bd9Sstevel@tonic-gate #define BCR0_CRFT1		0x10
3017c478bd9Sstevel@tonic-gate #define BCR0_CRFT0		0x08
3027c478bd9Sstevel@tonic-gate #define BCR0_DMAL2		0x04
3037c478bd9Sstevel@tonic-gate #define BCR0_DMAL1		0x02
3047c478bd9Sstevel@tonic-gate #define BCR0_DMAL0		0x01
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate /*
3077c478bd9Sstevel@tonic-gate  * Bits in the BCR1 register
3087c478bd9Sstevel@tonic-gate  */
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate #define BCR1_CTSF		0x20
3117c478bd9Sstevel@tonic-gate #define BCR1_CTFT1		0x10
3127c478bd9Sstevel@tonic-gate #define BCR1_CTFT0		0x08
3137c478bd9Sstevel@tonic-gate #define BCR1_POT2		0x04
3147c478bd9Sstevel@tonic-gate #define BCR1_POT1		0x02
3157c478bd9Sstevel@tonic-gate #define BCR1_POT0		0x01
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate /*
3187c478bd9Sstevel@tonic-gate  * Bits in the CFGA register
3197c478bd9Sstevel@tonic-gate  */
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate #define CFGA_EELOAD		0x80	/* enable eeprom embeded and direct programming */
3227c478bd9Sstevel@tonic-gate #define CFGA_JUMPER		0x40
3237c478bd9Sstevel@tonic-gate #define CFGA_MTGPIO		0x08
3247c478bd9Sstevel@tonic-gate #define CFGA_T10EN		0x02
3257c478bd9Sstevel@tonic-gate #define CFGA_AUTO		0x01
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate /*
3287c478bd9Sstevel@tonic-gate  * Bits in the CFGB register
3297c478bd9Sstevel@tonic-gate  */
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate #define CFGB_PD			0x80
3327c478bd9Sstevel@tonic-gate #define CFGB_POLEN		0x02
3337c478bd9Sstevel@tonic-gate #define CFGB_LNKEN		0x01
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate /*
3367c478bd9Sstevel@tonic-gate  * Bits in the CFGC register
3377c478bd9Sstevel@tonic-gate  */
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate #define CFGC_M10TIO		0x80
3407c478bd9Sstevel@tonic-gate #define CFGC_M10POL		0x40
3417c478bd9Sstevel@tonic-gate #define CFGC_PHY1		0x20
3427c478bd9Sstevel@tonic-gate #define CFGC_PHY0		0x10
3437c478bd9Sstevel@tonic-gate #define CFGC_BTSEL		0x08
3447c478bd9Sstevel@tonic-gate #define CFGC_BPS2		0x04	/* bootrom select[2] */
3457c478bd9Sstevel@tonic-gate #define CFGC_BPS1		0x02	/* bootrom select[1] */
3467c478bd9Sstevel@tonic-gate #define CFGC_BPS0		0x01	/* bootrom select[0] */
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate /*
3497c478bd9Sstevel@tonic-gate  * Bits in the CFGD register
3507c478bd9Sstevel@tonic-gate  */
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate #define CFGD_GPIOEN		0x80
3537c478bd9Sstevel@tonic-gate #define CFGD_DIAG		0x40
3547c478bd9Sstevel@tonic-gate #define CFGD_MAGIC		0x10
3557c478bd9Sstevel@tonic-gate #define CFGD_CFDX		0x04
3567c478bd9Sstevel@tonic-gate #define CFGD_CEREN		0x02
3577c478bd9Sstevel@tonic-gate #define CFGD_CETEN		0x01
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate /* Bits in RSR */
3607c478bd9Sstevel@tonic-gate #define RSR_RERR		0x00000001
3617c478bd9Sstevel@tonic-gate #define RSR_CRC			0x00000002
3627c478bd9Sstevel@tonic-gate #define RSR_FAE			0x00000004
3637c478bd9Sstevel@tonic-gate #define RSR_FOV			0x00000008
3647c478bd9Sstevel@tonic-gate #define RSR_LONG		0x00000010
3657c478bd9Sstevel@tonic-gate #define RSR_RUNT		0x00000020
3667c478bd9Sstevel@tonic-gate #define RSR_SERR		0x00000040
3677c478bd9Sstevel@tonic-gate #define RSR_BUFF		0x00000080
3687c478bd9Sstevel@tonic-gate #define RSR_EDP			0x00000100
3697c478bd9Sstevel@tonic-gate #define RSR_STP			0x00000200
3707c478bd9Sstevel@tonic-gate #define RSR_CHN			0x00000400
3717c478bd9Sstevel@tonic-gate #define RSR_PHY			0x00000800
3727c478bd9Sstevel@tonic-gate #define RSR_BAR			0x00001000
3737c478bd9Sstevel@tonic-gate #define RSR_MAR			0x00002000
3747c478bd9Sstevel@tonic-gate #define RSR_RXOK		0x00008000
3757c478bd9Sstevel@tonic-gate #define RSR_ABNORMAL		RSR_RERR+RSR_LONG+RSR_RUNT
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate /* Bits in TSR */
3787c478bd9Sstevel@tonic-gate #define TSR_NCR0		0x00000001
3797c478bd9Sstevel@tonic-gate #define TSR_NCR1		0x00000002
3807c478bd9Sstevel@tonic-gate #define TSR_NCR2		0x00000004
3817c478bd9Sstevel@tonic-gate #define TSR_NCR3		0x00000008
3827c478bd9Sstevel@tonic-gate #define TSR_COLS		0x00000010
3837c478bd9Sstevel@tonic-gate #define TSR_CDH			0x00000080
3847c478bd9Sstevel@tonic-gate #define TSR_ABT			0x00000100
3857c478bd9Sstevel@tonic-gate #define TSR_OWC			0x00000200
3867c478bd9Sstevel@tonic-gate #define TSR_CRS			0x00000400
3877c478bd9Sstevel@tonic-gate #define TSR_UDF			0x00000800
3887c478bd9Sstevel@tonic-gate #define TSR_TBUFF		0x00001000
3897c478bd9Sstevel@tonic-gate #define TSR_SERR		0x00002000
3907c478bd9Sstevel@tonic-gate #define TSR_JAB			0x00004000
3917c478bd9Sstevel@tonic-gate #define TSR_TERR		0x00008000
3927c478bd9Sstevel@tonic-gate #define TSR_ABNORMAL		TSR_TERR+TSR_OWC+TSR_ABT+TSR_JAB+TSR_CRS
3937c478bd9Sstevel@tonic-gate #define TSR_OWN_BIT		0x80000000
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate #define CB_DELAY_LOOP_WAIT	10	/* 10ms */
3967c478bd9Sstevel@tonic-gate /* enabled mask value of irq */
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate #define W_IMR_MASK_VALUE	0x1BFF	/* initial value of IMR */
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate /* Ethernet address filter type */
4017c478bd9Sstevel@tonic-gate #define PKT_TYPE_DIRECTED	0x0001	/* obsolete, directed address is always accepted */
4027c478bd9Sstevel@tonic-gate #define PKT_TYPE_MULTICAST	0x0002
4037c478bd9Sstevel@tonic-gate #define PKT_TYPE_ALL_MULTICAST	0x0004
4047c478bd9Sstevel@tonic-gate #define PKT_TYPE_BROADCAST	0x0008
4057c478bd9Sstevel@tonic-gate #define PKT_TYPE_PROMISCUOUS	0x0020
4067c478bd9Sstevel@tonic-gate #define PKT_TYPE_LONG		0x2000
4077c478bd9Sstevel@tonic-gate #define PKT_TYPE_RUNT		0x4000
4087c478bd9Sstevel@tonic-gate #define PKT_TYPE_ERROR		0x8000	/* accept error packets, e.g. CRC error */
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate /* Loopback mode */
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate #define NIC_LB_NONE		0x00
4137c478bd9Sstevel@tonic-gate #define NIC_LB_INTERNAL		0x01
4147c478bd9Sstevel@tonic-gate #define NIC_LB_PHY		0x02	/* MII or Internal-10BaseT loopback */
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate #define TX_RING_SIZE		2
4177c478bd9Sstevel@tonic-gate #define RX_RING_SIZE		2
4187c478bd9Sstevel@tonic-gate #define PKT_BUF_SZ		1536	/* Size of each temporary Rx buffer. */
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate /* Transmit and receive descriptors definition */
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate struct rhine_tx_desc
4237c478bd9Sstevel@tonic-gate {
4247c478bd9Sstevel@tonic-gate     union VTC_tx_status_tag
4257c478bd9Sstevel@tonic-gate     {
4267c478bd9Sstevel@tonic-gate 	struct
4277c478bd9Sstevel@tonic-gate 	{
4287c478bd9Sstevel@tonic-gate 	    unsigned long ncro:1;
4297c478bd9Sstevel@tonic-gate 	    unsigned long ncr1:1;
4307c478bd9Sstevel@tonic-gate 	    unsigned long ncr2:1;
4317c478bd9Sstevel@tonic-gate 	    unsigned long ncr3:1;
4327c478bd9Sstevel@tonic-gate 	    unsigned long cols:1;
4337c478bd9Sstevel@tonic-gate 	    unsigned long reserve_1:2;
4347c478bd9Sstevel@tonic-gate 	    unsigned long cdh:1;
4357c478bd9Sstevel@tonic-gate 	    unsigned long abt:1;
4367c478bd9Sstevel@tonic-gate 	    unsigned long owc:1;
4377c478bd9Sstevel@tonic-gate 	    unsigned long crs:1;
4387c478bd9Sstevel@tonic-gate 	    unsigned long udf:1;
4397c478bd9Sstevel@tonic-gate 	    unsigned long tbuff:1;
4407c478bd9Sstevel@tonic-gate 	    unsigned long serr:1;
4417c478bd9Sstevel@tonic-gate 	    unsigned long jab:1;
4427c478bd9Sstevel@tonic-gate 	    unsigned long terr:1;
4437c478bd9Sstevel@tonic-gate 	    unsigned long reserve_2:15;
4447c478bd9Sstevel@tonic-gate 	    unsigned long own_bit:1;
4457c478bd9Sstevel@tonic-gate 	}
4467c478bd9Sstevel@tonic-gate 	bits;
4477c478bd9Sstevel@tonic-gate 	unsigned long lw;
4487c478bd9Sstevel@tonic-gate     }
4497c478bd9Sstevel@tonic-gate     tx_status;
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate     union VTC_tx_ctrl_tag
4527c478bd9Sstevel@tonic-gate     {
4537c478bd9Sstevel@tonic-gate 	struct
4547c478bd9Sstevel@tonic-gate 	{
4557c478bd9Sstevel@tonic-gate 	    unsigned long tx_buf_size:11;
4567c478bd9Sstevel@tonic-gate 	    unsigned long extend_tx_buf_size:4;
4577c478bd9Sstevel@tonic-gate 	    unsigned long chn:1;
4587c478bd9Sstevel@tonic-gate 	    unsigned long crc:1;
4597c478bd9Sstevel@tonic-gate 	    unsigned long reserve_1:4;
4607c478bd9Sstevel@tonic-gate 	    unsigned long stp:1;
4617c478bd9Sstevel@tonic-gate 	    unsigned long edp:1;
4627c478bd9Sstevel@tonic-gate 	    unsigned long ic:1;
4637c478bd9Sstevel@tonic-gate 	    unsigned long reserve_2:8;
4647c478bd9Sstevel@tonic-gate 	}
4657c478bd9Sstevel@tonic-gate 	bits;
4667c478bd9Sstevel@tonic-gate 	unsigned long lw;
4677c478bd9Sstevel@tonic-gate     }
4687c478bd9Sstevel@tonic-gate     tx_ctrl;
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate     unsigned long buf_addr_1:32;
4717c478bd9Sstevel@tonic-gate     unsigned long buf_addr_2:32;
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate };
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate struct rhine_rx_desc
4767c478bd9Sstevel@tonic-gate {
4777c478bd9Sstevel@tonic-gate     union VTC_rx_status_tag
4787c478bd9Sstevel@tonic-gate     {
4797c478bd9Sstevel@tonic-gate 	struct
4807c478bd9Sstevel@tonic-gate 	{
4817c478bd9Sstevel@tonic-gate 	    unsigned long rerr:1;
4827c478bd9Sstevel@tonic-gate 	    unsigned long crc_error:1;
4837c478bd9Sstevel@tonic-gate 	    unsigned long fae:1;
4847c478bd9Sstevel@tonic-gate 	    unsigned long fov:1;
4857c478bd9Sstevel@tonic-gate 	    unsigned long toolong:1;
4867c478bd9Sstevel@tonic-gate 	    unsigned long runt:1;
4877c478bd9Sstevel@tonic-gate 	    unsigned long serr:1;
4887c478bd9Sstevel@tonic-gate 	    unsigned long buff:1;
4897c478bd9Sstevel@tonic-gate 	    unsigned long edp:1;
4907c478bd9Sstevel@tonic-gate 	    unsigned long stp:1;
4917c478bd9Sstevel@tonic-gate 	    unsigned long chn:1;
4927c478bd9Sstevel@tonic-gate 	    unsigned long phy:1;
4937c478bd9Sstevel@tonic-gate 	    unsigned long bar:1;
4947c478bd9Sstevel@tonic-gate 	    unsigned long mar:1;
4957c478bd9Sstevel@tonic-gate 	    unsigned long reserve_1:1;
4967c478bd9Sstevel@tonic-gate 	    unsigned long rxok:1;
4977c478bd9Sstevel@tonic-gate 	    unsigned long frame_length:11;
4987c478bd9Sstevel@tonic-gate 	    unsigned long reverve_2:4;
4997c478bd9Sstevel@tonic-gate 	    unsigned long own_bit:1;
5007c478bd9Sstevel@tonic-gate 	}
5017c478bd9Sstevel@tonic-gate 	bits;
5027c478bd9Sstevel@tonic-gate 	unsigned long lw;
5037c478bd9Sstevel@tonic-gate     }
5047c478bd9Sstevel@tonic-gate     rx_status;
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate     union VTC_rx_ctrl_tag
5077c478bd9Sstevel@tonic-gate     {
5087c478bd9Sstevel@tonic-gate 	struct
5097c478bd9Sstevel@tonic-gate 	{
5107c478bd9Sstevel@tonic-gate 	    unsigned long rx_buf_size:11;
5117c478bd9Sstevel@tonic-gate 	    unsigned long extend_rx_buf_size:4;
5127c478bd9Sstevel@tonic-gate 	    unsigned long reserved_1:17;
5137c478bd9Sstevel@tonic-gate 	}
5147c478bd9Sstevel@tonic-gate 	bits;
5157c478bd9Sstevel@tonic-gate 	unsigned long lw;
5167c478bd9Sstevel@tonic-gate     }
5177c478bd9Sstevel@tonic-gate     rx_ctrl;
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate     unsigned long buf_addr_1:32;
5207c478bd9Sstevel@tonic-gate     unsigned long buf_addr_2:32;
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate };
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate /* The I/O extent. */
5267c478bd9Sstevel@tonic-gate #define rhine_TOTAL_SIZE 0x80
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate #ifdef	HAVE_DEVLIST
5297c478bd9Sstevel@tonic-gate struct netdev_entry rhine_drv =
5307c478bd9Sstevel@tonic-gate     { "rhine", rhine_probe, rhine_TOTAL_SIZE, NULL };
5317c478bd9Sstevel@tonic-gate #endif
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate static int rhine_debug = 1;
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate /*
5367c478bd9Sstevel@tonic-gate 				Theory of Operation
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate I. Board Compatibility
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate This driver is designed for the VIA 86c100A Rhine-II PCI Fast Ethernet
5417c478bd9Sstevel@tonic-gate controller.
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate II. Board-specific settings
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate Boards with this chip are functional only in a bus-master PCI slot.
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate Many operational settings are loaded from the EEPROM to the Config word at
5487c478bd9Sstevel@tonic-gate offset 0x78.  This driver assumes that they are correct.
5497c478bd9Sstevel@tonic-gate If this driver is compiled to use PCI memory space operations the EEPROM
5507c478bd9Sstevel@tonic-gate must be configured to enable memory ops.
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate III. Driver operation
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate IIIa. Ring buffers
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate This driver uses two statically allocated fixed-size descriptor lists
5577c478bd9Sstevel@tonic-gate formed into rings by a branch from the final descriptor to the beginning of
5587c478bd9Sstevel@tonic-gate the list.  The ring sizes are set at compile time by RX/TX_RING_SIZE.
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate IIIb/c. Transmit/Receive Structure
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate This driver attempts to use a zero-copy receive and transmit scheme.
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate Alas, all data buffers are required to start on a 32 bit boundary, so
5657c478bd9Sstevel@tonic-gate the driver must often copy transmit packets into bounce buffers.
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate The driver allocates full frame size skbuffs for the Rx ring buffers at
5687c478bd9Sstevel@tonic-gate open() time and passes the skb->data field to the chip as receive data
5697c478bd9Sstevel@tonic-gate buffers.  When an incoming frame is less than RX_COPYBREAK bytes long,
5707c478bd9Sstevel@tonic-gate a fresh skbuff is allocated and the frame is copied to the new skbuff.
5717c478bd9Sstevel@tonic-gate When the incoming frame is larger, the skbuff is passed directly up the
5727c478bd9Sstevel@tonic-gate protocol stack.  Buffers consumed this way are replaced by newly allocated
5737c478bd9Sstevel@tonic-gate skbuffs in the last phase of netdev_rx().
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate The RX_COPYBREAK value is chosen to trade-off the memory wasted by
5767c478bd9Sstevel@tonic-gate using a full-sized skbuff for small frames vs. the copying costs of larger
5777c478bd9Sstevel@tonic-gate frames.  New boards are typically used in generously configured machines
5787c478bd9Sstevel@tonic-gate and the underfilled buffers have negligible impact compared to the benefit of
5797c478bd9Sstevel@tonic-gate a single allocation size, so the default value of zero results in never
5807c478bd9Sstevel@tonic-gate copying packets.  When copying is done, the cost is usually mitigated by using
5817c478bd9Sstevel@tonic-gate a combined copy/checksum routine.  Copying also preloads the cache, which is
5827c478bd9Sstevel@tonic-gate most useful with small frames.
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate Since the VIA chips are only able to transfer data to buffers on 32 bit
5857c478bd9Sstevel@tonic-gate boundaries, the the IP header at offset 14 in an ethernet frame isn't
5867c478bd9Sstevel@tonic-gate longword aligned for further processing.  Copying these unaligned buffers
5877c478bd9Sstevel@tonic-gate has the beneficial effect of 16-byte aligning the IP header.
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate IIId. Synchronization
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate The driver runs as two independent, single-threaded flows of control.  One
5927c478bd9Sstevel@tonic-gate is the send-packet routine, which enforces single-threaded use by the
5937c478bd9Sstevel@tonic-gate dev->tbusy flag.  The other thread is the interrupt handler, which is single
5947c478bd9Sstevel@tonic-gate threaded by the hardware and interrupt handling software.
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate The send packet thread has partial control over the Tx ring and 'dev->tbusy'
5977c478bd9Sstevel@tonic-gate flag.  It sets the tbusy flag whenever it's queuing a Tx packet. If the next
5987c478bd9Sstevel@tonic-gate queue slot is empty, it clears the tbusy flag when finished otherwise it sets
5997c478bd9Sstevel@tonic-gate the 'lp->tx_full' flag.
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate The interrupt handler has exclusive control over the Rx ring and records stats
6027c478bd9Sstevel@tonic-gate from the Tx ring.  After reaping the stats, it marks the Tx queue entry as
6037c478bd9Sstevel@tonic-gate empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it
6047c478bd9Sstevel@tonic-gate clears both the tx_full and tbusy flags.
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate IV. Notes
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate IVb. References
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate Preliminary VT86C100A manual from http://www.via.com.tw/
6117c478bd9Sstevel@tonic-gate http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html
6127c478bd9Sstevel@tonic-gate http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate IVc. Errata
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate The VT86C100A manual is not reliable information.
6177c478bd9Sstevel@tonic-gate The chip does not handle unaligned transmit or receive buffers, resulting
6187c478bd9Sstevel@tonic-gate in significant performance degradation for bounce buffer copies on transmit
6197c478bd9Sstevel@tonic-gate and unaligned IP headers on receive.
6207c478bd9Sstevel@tonic-gate The chip does not pad to minimum transmit length.
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate */
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate /* The rest of these values should never change. */
6257c478bd9Sstevel@tonic-gate #define NUM_TX_DESC	2	/* Number of Tx descriptor registers. */
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate static struct rhine_private
6287c478bd9Sstevel@tonic-gate {
6297c478bd9Sstevel@tonic-gate     char devname[8];		/* Used only for kernel debugging. */
6307c478bd9Sstevel@tonic-gate     const char *product_name;
6317c478bd9Sstevel@tonic-gate     struct rhine_rx_desc *rx_ring;
6327c478bd9Sstevel@tonic-gate     struct rhine_tx_desc *tx_ring;
6337c478bd9Sstevel@tonic-gate     char *rx_buffs[RX_RING_SIZE];
6347c478bd9Sstevel@tonic-gate     char *tx_buffs[TX_RING_SIZE];
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate     /* temporary Rx buffers. */
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate     int chip_id;
6397c478bd9Sstevel@tonic-gate     int chip_revision;
6407c478bd9Sstevel@tonic-gate     unsigned short ioaddr;
6417c478bd9Sstevel@tonic-gate     unsigned int cur_rx, cur_tx;	/* The next free and used entries */
6427c478bd9Sstevel@tonic-gate     unsigned int dirty_rx, dirty_tx;
6437c478bd9Sstevel@tonic-gate     /* The saved address of a sent-in-place packet/buffer, for skfree(). */
6447c478bd9Sstevel@tonic-gate     struct sk_buff *tx_skbuff[TX_RING_SIZE];
6457c478bd9Sstevel@tonic-gate     unsigned char mc_filter[8];	/* Current multicast filter. */
6467c478bd9Sstevel@tonic-gate     char phys[4];		/* MII device addresses. */
6477c478bd9Sstevel@tonic-gate     unsigned int tx_full:1;	/* The Tx queue is full. */
6487c478bd9Sstevel@tonic-gate     unsigned int full_duplex:1;	/* Full-duplex operation requested. */
6497c478bd9Sstevel@tonic-gate     unsigned int default_port:4;	/* Last dev->if_port value. */
6507c478bd9Sstevel@tonic-gate     unsigned int media2:4;	/* Secondary monitored media port. */
6517c478bd9Sstevel@tonic-gate     unsigned int medialock:1;	/* Don't sense media type. */
6527c478bd9Sstevel@tonic-gate     unsigned int mediasense:1;	/* Media sensing in progress. */
6537c478bd9Sstevel@tonic-gate }
6547c478bd9Sstevel@tonic-gate rhine;
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate static void rhine_probe1 (struct nic *nic, int ioaddr,
6577c478bd9Sstevel@tonic-gate 				 int chip_id, int options);
6587c478bd9Sstevel@tonic-gate static int QueryAuto (int);
6597c478bd9Sstevel@tonic-gate static int ReadMII (int byMIIIndex, int);
6607c478bd9Sstevel@tonic-gate static void WriteMII (char, char, char, int);
6617c478bd9Sstevel@tonic-gate static void MIIDelay (void);
6627c478bd9Sstevel@tonic-gate static void rhine_init_ring (struct nic *dev);
6637c478bd9Sstevel@tonic-gate static void rhine_disable (struct dev *dev);
6647c478bd9Sstevel@tonic-gate static void rhine_reset (struct nic *nic);
6657c478bd9Sstevel@tonic-gate static int rhine_poll (struct nic *nic, int retreive);
6667c478bd9Sstevel@tonic-gate static void rhine_transmit (struct nic *nic, const char *d, unsigned int t,
6677c478bd9Sstevel@tonic-gate 			    unsigned int s, const char *p);
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
6707c478bd9Sstevel@tonic-gate static void
rhine_init_ring(struct nic * nic)6717c478bd9Sstevel@tonic-gate rhine_init_ring (struct nic *nic)
6727c478bd9Sstevel@tonic-gate {
6737c478bd9Sstevel@tonic-gate     struct rhine_private *tp = (struct rhine_private *) nic->priv_data;
6747c478bd9Sstevel@tonic-gate     int i;
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate     tp->tx_full = 0;
6777c478bd9Sstevel@tonic-gate     tp->cur_rx = tp->cur_tx = 0;
6787c478bd9Sstevel@tonic-gate     tp->dirty_rx = tp->dirty_tx = 0;
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate     for (i = 0; i < RX_RING_SIZE; i++)
6817c478bd9Sstevel@tonic-gate     {
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	tp->rx_ring[i].rx_status.bits.own_bit = 1;
6847c478bd9Sstevel@tonic-gate 	tp->rx_ring[i].rx_ctrl.bits.rx_buf_size = 1536;
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 	tp->rx_ring[i].buf_addr_1 = virt_to_bus (tp->rx_buffs[i]);
6877c478bd9Sstevel@tonic-gate 	tp->rx_ring[i].buf_addr_2 = virt_to_bus (&tp->rx_ring[i + 1]);
6887c478bd9Sstevel@tonic-gate 	/* printf("[%d]buf1=%hX,buf2=%hX",i,tp->rx_ring[i].buf_addr_1,tp->rx_ring[i].buf_addr_2); */
6897c478bd9Sstevel@tonic-gate     }
6907c478bd9Sstevel@tonic-gate     /* Mark the last entry as wrapping the ring. */
6917c478bd9Sstevel@tonic-gate     /* tp->rx_ring[i-1].rx_ctrl.bits.rx_buf_size =1518; */
6927c478bd9Sstevel@tonic-gate     tp->rx_ring[i - 1].buf_addr_2 = virt_to_bus (&tp->rx_ring[0]);
6937c478bd9Sstevel@tonic-gate     /*printf("[%d]buf1=%hX,buf2=%hX",i-1,tp->rx_ring[i-1].buf_addr_1,tp->rx_ring[i-1].buf_addr_2); */
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate     /* The Tx buffer descriptor is filled in as needed, but we
6967c478bd9Sstevel@tonic-gate        do need to clear the ownership bit. */
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate     for (i = 0; i < TX_RING_SIZE; i++)
6997c478bd9Sstevel@tonic-gate     {
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 	tp->tx_ring[i].tx_status.lw = 0;
7027c478bd9Sstevel@tonic-gate 	tp->tx_ring[i].tx_ctrl.lw = 0x00e08000;
7037c478bd9Sstevel@tonic-gate 	tp->tx_ring[i].buf_addr_1 = virt_to_bus (tp->tx_buffs[i]);
7047c478bd9Sstevel@tonic-gate 	tp->tx_ring[i].buf_addr_2 = virt_to_bus (&tp->tx_ring[i + 1]);
7057c478bd9Sstevel@tonic-gate 	/* printf("[%d]buf1=%hX,buf2=%hX",i,tp->tx_ring[i].buf_addr_1,tp->tx_ring[i].buf_addr_2); */
7067c478bd9Sstevel@tonic-gate     }
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate     tp->tx_ring[i - 1].buf_addr_2 = virt_to_bus (&tp->tx_ring[0]);
7097c478bd9Sstevel@tonic-gate     /* printf("[%d]buf1=%hX,buf2=%hX",i,tp->tx_ring[i-1].buf_addr_1,tp->tx_ring[i-1].buf_addr_2); */
7107c478bd9Sstevel@tonic-gate }
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate int
QueryAuto(int ioaddr)7137c478bd9Sstevel@tonic-gate QueryAuto (int ioaddr)
7147c478bd9Sstevel@tonic-gate {
7157c478bd9Sstevel@tonic-gate     int byMIIIndex;
7167c478bd9Sstevel@tonic-gate     int MIIReturn;
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 	int advertising,mii_reg5;
7197c478bd9Sstevel@tonic-gate 	int negociated;
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate     byMIIIndex = 0x04;
7227c478bd9Sstevel@tonic-gate     MIIReturn = ReadMII (byMIIIndex, ioaddr);
7237c478bd9Sstevel@tonic-gate 	advertising=MIIReturn;
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate     byMIIIndex = 0x05;
7267c478bd9Sstevel@tonic-gate     MIIReturn = ReadMII (byMIIIndex, ioaddr);
7277c478bd9Sstevel@tonic-gate 	mii_reg5=MIIReturn;
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 	negociated=mii_reg5 & advertising;
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 	if ( (negociated & 0x100) || (negociated & 0x1C0) == 0x40 )
7327c478bd9Sstevel@tonic-gate 		return 1;
7337c478bd9Sstevel@tonic-gate 	else
7347c478bd9Sstevel@tonic-gate 		return 0;
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate }
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate int
ReadMII(int byMIIIndex,int ioaddr)7397c478bd9Sstevel@tonic-gate ReadMII (int byMIIIndex, int ioaddr)
7407c478bd9Sstevel@tonic-gate {
7417c478bd9Sstevel@tonic-gate     int ReturnMII;
7427c478bd9Sstevel@tonic-gate     char byMIIAdrbak;
7437c478bd9Sstevel@tonic-gate     char byMIICRbak;
7447c478bd9Sstevel@tonic-gate     char byMIItemp;
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate     byMIIAdrbak = inb (byMIIAD);
7477c478bd9Sstevel@tonic-gate     byMIICRbak = inb (byMIICR);
7487c478bd9Sstevel@tonic-gate     outb (byMIICRbak & 0x7f, byMIICR);
7497c478bd9Sstevel@tonic-gate     MIIDelay ();
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate     outb (byMIIIndex, byMIIAD);
7527c478bd9Sstevel@tonic-gate     MIIDelay ();
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate     outb (inb (byMIICR) | 0x40, byMIICR);
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate     byMIItemp = inb (byMIICR);
7577c478bd9Sstevel@tonic-gate     byMIItemp = byMIItemp & 0x40;
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate     while (byMIItemp != 0)
7607c478bd9Sstevel@tonic-gate     {
7617c478bd9Sstevel@tonic-gate 	byMIItemp = inb (byMIICR);
7627c478bd9Sstevel@tonic-gate 	byMIItemp = byMIItemp & 0x40;
7637c478bd9Sstevel@tonic-gate     }
7647c478bd9Sstevel@tonic-gate     MIIDelay ();
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate     ReturnMII = inw (wMIIDATA);
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate     outb (byMIIAdrbak, byMIIAD);
7697c478bd9Sstevel@tonic-gate     outb (byMIICRbak, byMIICR);
7707c478bd9Sstevel@tonic-gate     MIIDelay ();
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate     return (ReturnMII);
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate }
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate void
WriteMII(char byMIISetByte,char byMIISetBit,char byMIIOP,int ioaddr)7777c478bd9Sstevel@tonic-gate WriteMII (char byMIISetByte, char byMIISetBit, char byMIIOP, int ioaddr)
7787c478bd9Sstevel@tonic-gate {
7797c478bd9Sstevel@tonic-gate     int ReadMIItmp;
7807c478bd9Sstevel@tonic-gate     int MIIMask;
7817c478bd9Sstevel@tonic-gate     char byMIIAdrbak;
7827c478bd9Sstevel@tonic-gate     char byMIICRbak;
7837c478bd9Sstevel@tonic-gate     char byMIItemp;
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate     byMIIAdrbak = inb (byMIIAD);
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate     byMIICRbak = inb (byMIICR);
7897c478bd9Sstevel@tonic-gate     outb (byMIICRbak & 0x7f, byMIICR);
7907c478bd9Sstevel@tonic-gate     MIIDelay ();
7917c478bd9Sstevel@tonic-gate     outb (byMIISetByte, byMIIAD);
7927c478bd9Sstevel@tonic-gate     MIIDelay ();
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate     outb (inb (byMIICR) | 0x40, byMIICR);
7957c478bd9Sstevel@tonic-gate 
7967c478bd9Sstevel@tonic-gate     byMIItemp = inb (byMIICR);
7977c478bd9Sstevel@tonic-gate     byMIItemp = byMIItemp & 0x40;
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate     while (byMIItemp != 0)
8007c478bd9Sstevel@tonic-gate     {
8017c478bd9Sstevel@tonic-gate 	byMIItemp = inb (byMIICR);
8027c478bd9Sstevel@tonic-gate 	byMIItemp = byMIItemp & 0x40;
8037c478bd9Sstevel@tonic-gate     }
8047c478bd9Sstevel@tonic-gate     MIIDelay ();
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate     ReadMIItmp = inw (wMIIDATA);
8077c478bd9Sstevel@tonic-gate     MIIMask = 0x0001;
8087c478bd9Sstevel@tonic-gate     MIIMask = MIIMask << byMIISetBit;
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate     if (byMIIOP == 0)
8127c478bd9Sstevel@tonic-gate     {
8137c478bd9Sstevel@tonic-gate 	MIIMask = ~MIIMask;
8147c478bd9Sstevel@tonic-gate 	ReadMIItmp = ReadMIItmp & MIIMask;
8157c478bd9Sstevel@tonic-gate     }
8167c478bd9Sstevel@tonic-gate     else
8177c478bd9Sstevel@tonic-gate     {
8187c478bd9Sstevel@tonic-gate 	ReadMIItmp = ReadMIItmp | MIIMask;
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate     }
8217c478bd9Sstevel@tonic-gate     outw (ReadMIItmp, wMIIDATA);
8227c478bd9Sstevel@tonic-gate     MIIDelay ();
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate     outb (inb (byMIICR) | 0x20, byMIICR);
8257c478bd9Sstevel@tonic-gate     byMIItemp = inb (byMIICR);
8267c478bd9Sstevel@tonic-gate     byMIItemp = byMIItemp & 0x20;
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate     while (byMIItemp != 0)
8297c478bd9Sstevel@tonic-gate     {
8307c478bd9Sstevel@tonic-gate 	byMIItemp = inb (byMIICR);
8317c478bd9Sstevel@tonic-gate 	byMIItemp = byMIItemp & 0x20;
8327c478bd9Sstevel@tonic-gate     }
8337c478bd9Sstevel@tonic-gate     MIIDelay ();
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate     outb (byMIIAdrbak & 0x7f, byMIIAD);
8367c478bd9Sstevel@tonic-gate     outb (byMIICRbak, byMIICR);
8377c478bd9Sstevel@tonic-gate     MIIDelay ();
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate }
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate void
MIIDelay(void)8427c478bd9Sstevel@tonic-gate MIIDelay (void)
8437c478bd9Sstevel@tonic-gate {
8447c478bd9Sstevel@tonic-gate     int i;
8457c478bd9Sstevel@tonic-gate     for (i = 0; i < 0x7fff; i++)
8467c478bd9Sstevel@tonic-gate     {
8477c478bd9Sstevel@tonic-gate 	inb (0x61);
8487c478bd9Sstevel@tonic-gate 	inb (0x61);
8497c478bd9Sstevel@tonic-gate 	inb (0x61);
8507c478bd9Sstevel@tonic-gate 	inb (0x61);
8517c478bd9Sstevel@tonic-gate     }
8527c478bd9Sstevel@tonic-gate }
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate /* Offsets to the device registers. */
8557c478bd9Sstevel@tonic-gate enum register_offsets {
8567c478bd9Sstevel@tonic-gate         StationAddr=0x00, RxConfig=0x06, TxConfig=0x07, ChipCmd=0x08,
8577c478bd9Sstevel@tonic-gate         IntrStatus=0x0C, IntrEnable=0x0E,
8587c478bd9Sstevel@tonic-gate         MulticastFilter0=0x10, MulticastFilter1=0x14,
8597c478bd9Sstevel@tonic-gate         RxRingPtr=0x18, TxRingPtr=0x1C, GFIFOTest=0x54,
8607c478bd9Sstevel@tonic-gate         MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E,
8617c478bd9Sstevel@tonic-gate         MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72, MACRegEEcsr=0x74,
8627c478bd9Sstevel@tonic-gate         ConfigA=0x78, ConfigB=0x79, ConfigC=0x7A, ConfigD=0x7B,
8637c478bd9Sstevel@tonic-gate         RxMissed=0x7C, RxCRCErrs=0x7E, MiscCmd=0x81,
8647c478bd9Sstevel@tonic-gate         StickyHW=0x83, IntrStatus2=0x84, WOLcrClr=0xA4, WOLcgClr=0xA7,
8657c478bd9Sstevel@tonic-gate         PwrcsrClr=0xAC,
8667c478bd9Sstevel@tonic-gate };
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate /* Bits in the interrupt status/mask registers. */
8697c478bd9Sstevel@tonic-gate enum intr_status_bits {
8707c478bd9Sstevel@tonic-gate         IntrRxDone=0x0001, IntrRxErr=0x0004, IntrRxEmpty=0x0020,
8717c478bd9Sstevel@tonic-gate         IntrTxDone=0x0002, IntrTxError=0x0008, IntrTxUnderrun=0x0210,
8727c478bd9Sstevel@tonic-gate         IntrPCIErr=0x0040,
8737c478bd9Sstevel@tonic-gate         IntrStatsMax=0x0080, IntrRxEarly=0x0100,
8747c478bd9Sstevel@tonic-gate         IntrRxOverflow=0x0400, IntrRxDropped=0x0800, IntrRxNoBuf=0x1000,
8757c478bd9Sstevel@tonic-gate         IntrTxAborted=0x2000, IntrLinkChange=0x4000,
8767c478bd9Sstevel@tonic-gate         IntrRxWakeUp=0x8000,
8777c478bd9Sstevel@tonic-gate         IntrNormalSummary=0x0003, IntrAbnormalSummary=0xC260,
8787c478bd9Sstevel@tonic-gate         IntrTxDescRace=0x080000,        /* mapped from IntrStatus2 */
8797c478bd9Sstevel@tonic-gate         IntrTxErrSummary=0x082218,
8807c478bd9Sstevel@tonic-gate };
8817c478bd9Sstevel@tonic-gate #define DEFAULT_INTR (IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow | \
8827c478bd9Sstevel@tonic-gate                    IntrRxDropped | IntrRxNoBuf)
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate /***************************************************************************
8857c478bd9Sstevel@tonic-gate  IRQ - PXE IRQ Handler
8867c478bd9Sstevel@tonic-gate ***************************************************************************/
rhine_irq(struct nic * nic,irq_action_t action)8877c478bd9Sstevel@tonic-gate void rhine_irq ( struct nic *nic, irq_action_t action ) {
8887c478bd9Sstevel@tonic-gate      struct rhine_private *tp = (struct rhine_private *) nic->priv_data;
8897c478bd9Sstevel@tonic-gate      /* Enable interrupts by setting the interrupt mask. */
8907c478bd9Sstevel@tonic-gate      unsigned int intr_status;
8917c478bd9Sstevel@tonic-gate 
8927c478bd9Sstevel@tonic-gate      switch ( action ) {
8937c478bd9Sstevel@tonic-gate           case DISABLE :
8947c478bd9Sstevel@tonic-gate           case ENABLE :
8957c478bd9Sstevel@tonic-gate                intr_status = inw(nic->ioaddr + IntrStatus);
8967c478bd9Sstevel@tonic-gate                /* On Rhine-II, Bit 3 indicates Tx descriptor write-back race. */
8977c478bd9Sstevel@tonic-gate                if (tp->chip_id == 0x3065)
8987c478bd9Sstevel@tonic-gate                    intr_status |= inb(nic->ioaddr + IntrStatus2) << 16;
8997c478bd9Sstevel@tonic-gate                intr_status = (intr_status & ~DEFAULT_INTR);
9007c478bd9Sstevel@tonic-gate                if ( action == ENABLE )
9017c478bd9Sstevel@tonic-gate                    intr_status = intr_status | DEFAULT_INTR;
9027c478bd9Sstevel@tonic-gate                outw(intr_status, nic->ioaddr + IntrEnable);
9037c478bd9Sstevel@tonic-gate                break;
9047c478bd9Sstevel@tonic-gate          case FORCE :
9057c478bd9Sstevel@tonic-gate                outw(0x0010, nic->ioaddr + 0x84);
9067c478bd9Sstevel@tonic-gate                break;
9077c478bd9Sstevel@tonic-gate          }
9087c478bd9Sstevel@tonic-gate }
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate static int
rhine_probe(struct dev * dev,struct pci_device * pci)9117c478bd9Sstevel@tonic-gate rhine_probe (struct dev *dev, struct pci_device *pci)
9127c478bd9Sstevel@tonic-gate {
9137c478bd9Sstevel@tonic-gate     struct nic *nic = (struct nic *)dev;
9147c478bd9Sstevel@tonic-gate     struct rhine_private *tp = &rhine;
9157c478bd9Sstevel@tonic-gate     if (!pci->ioaddr)
9167c478bd9Sstevel@tonic-gate 	return 0;
9177c478bd9Sstevel@tonic-gate     rhine_probe1 (nic, pci->ioaddr, pci->dev_id, -1);
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate     adjust_pci_device(pci);
9207c478bd9Sstevel@tonic-gate     rhine_reset (nic);
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate     dev->disable  = rhine_disable;
9237c478bd9Sstevel@tonic-gate     nic->poll     = rhine_poll;
9247c478bd9Sstevel@tonic-gate     nic->transmit = rhine_transmit;
9257c478bd9Sstevel@tonic-gate     nic->irqno	  = pci->irq;
9267c478bd9Sstevel@tonic-gate     nic->irq      = rhine_irq;
9277c478bd9Sstevel@tonic-gate     nic->ioaddr   = tp->ioaddr;
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate     return 1;
9317c478bd9Sstevel@tonic-gate }
9327c478bd9Sstevel@tonic-gate 
set_rx_mode(struct nic * nic __unused)9337c478bd9Sstevel@tonic-gate static void set_rx_mode(struct nic *nic __unused) {
9347c478bd9Sstevel@tonic-gate     	struct rhine_private *tp = (struct rhine_private *) nic->priv_data;
9357c478bd9Sstevel@tonic-gate 	unsigned char rx_mode;
9367c478bd9Sstevel@tonic-gate     	int ioaddr = tp->ioaddr;
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 	/* ! IFF_PROMISC */
9397c478bd9Sstevel@tonic-gate 	outl(0xffffffff, byMAR0);
9407c478bd9Sstevel@tonic-gate 	outl(0xffffffff, byMAR4);
9417c478bd9Sstevel@tonic-gate 	rx_mode = 0x0C;
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate 	outb(0x60 /* thresh */ | rx_mode, byRCR );
9447c478bd9Sstevel@tonic-gate }
9457c478bd9Sstevel@tonic-gate 
9467c478bd9Sstevel@tonic-gate static void
rhine_probe1(struct nic * nic,int ioaddr,int chip_id,int options)9477c478bd9Sstevel@tonic-gate rhine_probe1 (struct nic *nic, int ioaddr, int chip_id, int options)
9487c478bd9Sstevel@tonic-gate {
9497c478bd9Sstevel@tonic-gate     struct rhine_private *tp;
9507c478bd9Sstevel@tonic-gate     static int did_version = 0;	/* Already printed version info. */
9517c478bd9Sstevel@tonic-gate     int i;
9527c478bd9Sstevel@tonic-gate     unsigned int timeout;
9537c478bd9Sstevel@tonic-gate     int FDXFlag;
9547c478bd9Sstevel@tonic-gate     int byMIIvalue, LineSpeed, MIICRbak;
9557c478bd9Sstevel@tonic-gate 
9567c478bd9Sstevel@tonic-gate     if (rhine_debug > 0 && did_version++ == 0)
9577c478bd9Sstevel@tonic-gate 	printf (version);
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate     /* D-Link provided reset code (with comment additions) */
9607c478bd9Sstevel@tonic-gate     if((chip_id != 0x3043) && (chip_id != 0x6100)) {
9617c478bd9Sstevel@tonic-gate 	unsigned char byOrgValue;
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate 	if(rhine_debug > 0)
9647c478bd9Sstevel@tonic-gate 		printf("Enabling Sticky Bit Workaround for Chip_id: 0x%hX\n"
9657c478bd9Sstevel@tonic-gate 				, chip_id);
9667c478bd9Sstevel@tonic-gate 	/* clear sticky bit before reset & read ethernet address */
9677c478bd9Sstevel@tonic-gate 	byOrgValue = inb(bySTICKHW);
9687c478bd9Sstevel@tonic-gate 	byOrgValue = byOrgValue & 0xFC;
9697c478bd9Sstevel@tonic-gate 	outb(byOrgValue, bySTICKHW);
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 	/* (bits written are cleared?) */
9727c478bd9Sstevel@tonic-gate 	/* disable force PME-enable */
9737c478bd9Sstevel@tonic-gate 	outb(0x80, byWOLcgClr);
9747c478bd9Sstevel@tonic-gate 	/* disable power-event config bit */
9757c478bd9Sstevel@tonic-gate 	outb(0xFF, byWOLcrClr);
9767c478bd9Sstevel@tonic-gate 	/* clear power status (undocumented in vt6102 docs?) */
9777c478bd9Sstevel@tonic-gate 	outb(0xFF, byPwrcsrClr);
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate     }
9807c478bd9Sstevel@tonic-gate 
9817c478bd9Sstevel@tonic-gate     /* Perhaps this should be read from the EEPROM? */
9827c478bd9Sstevel@tonic-gate     for (i = 0; i < ETH_ALEN; i++)
9837c478bd9Sstevel@tonic-gate 	nic->node_addr[i] = inb (byPAR0 + i);
9847c478bd9Sstevel@tonic-gate     printf ("IO address %hX Ethernet Address: %!\n", ioaddr, nic->node_addr);
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate     /* restart MII auto-negotiation */
9877c478bd9Sstevel@tonic-gate     WriteMII (0, 9, 1, ioaddr);
9887c478bd9Sstevel@tonic-gate     printf ("Analyzing Media type,this will take several seconds........");
9897c478bd9Sstevel@tonic-gate     for (i = 0; i < 5; i++)
9907c478bd9Sstevel@tonic-gate     {
9917c478bd9Sstevel@tonic-gate 	/* need to wait 1 millisecond - we will round it up to 50-100ms */
9927c478bd9Sstevel@tonic-gate 	timeout = currticks() + 2;
9937c478bd9Sstevel@tonic-gate 	for (timeout = currticks() + 2; currticks() < timeout;)
9947c478bd9Sstevel@tonic-gate 	    /* nothing */;
9957c478bd9Sstevel@tonic-gate 	if (ReadMII (1, ioaddr) & 0x0020)
9967c478bd9Sstevel@tonic-gate 	    break;
9977c478bd9Sstevel@tonic-gate     }
9987c478bd9Sstevel@tonic-gate     printf ("OK\n");
9997c478bd9Sstevel@tonic-gate 
10007c478bd9Sstevel@tonic-gate #if	0
10017c478bd9Sstevel@tonic-gate 	/* JJM : for Debug */
10027c478bd9Sstevel@tonic-gate 	printf("MII : Address %hhX ",inb(ioaddr+0x6c));
10037c478bd9Sstevel@tonic-gate 	{
10047c478bd9Sstevel@tonic-gate 	 unsigned char st1,st2,adv1,adv2,l1,l2;
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 	 st1=ReadMII(1,ioaddr)>>8;
10077c478bd9Sstevel@tonic-gate 	 st2=ReadMII(1,ioaddr)&0xFF;
10087c478bd9Sstevel@tonic-gate 	 adv1=ReadMII(4,ioaddr)>>8;
10097c478bd9Sstevel@tonic-gate 	 adv2=ReadMII(4,ioaddr)&0xFF;
10107c478bd9Sstevel@tonic-gate 	 l1=ReadMII(5,ioaddr)>>8;
10117c478bd9Sstevel@tonic-gate 	 l2=ReadMII(5,ioaddr)&0xFF;
10127c478bd9Sstevel@tonic-gate 	 printf(" status 0x%hhX%hhX, advertising 0x%hhX%hhX, link 0x%hhX%hhX\n", st1,st2,adv1,adv2,l1,l2);
10137c478bd9Sstevel@tonic-gate 	}
10147c478bd9Sstevel@tonic-gate #endif
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate 
10177c478bd9Sstevel@tonic-gate     /* query MII to know LineSpeed,duplex mode */
10187c478bd9Sstevel@tonic-gate     byMIIvalue = inb (ioaddr + 0x6d);
10197c478bd9Sstevel@tonic-gate     LineSpeed = byMIIvalue & MIISR_SPEED;
10207c478bd9Sstevel@tonic-gate     if (LineSpeed != 0)						//JJM
10217c478bd9Sstevel@tonic-gate     {
10227c478bd9Sstevel@tonic-gate 	printf ("Linespeed=10Mbs");
10237c478bd9Sstevel@tonic-gate     }
10247c478bd9Sstevel@tonic-gate     else
10257c478bd9Sstevel@tonic-gate     {
10267c478bd9Sstevel@tonic-gate 	printf ("Linespeed=100Mbs");
10277c478bd9Sstevel@tonic-gate     }
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate     FDXFlag = QueryAuto (ioaddr);
10307c478bd9Sstevel@tonic-gate     if (FDXFlag == 1)
10317c478bd9Sstevel@tonic-gate     {
10327c478bd9Sstevel@tonic-gate 	printf (" Fullduplex\n");
10337c478bd9Sstevel@tonic-gate 	outw (CR_FDX, byCR0);
10347c478bd9Sstevel@tonic-gate     }
10357c478bd9Sstevel@tonic-gate     else
10367c478bd9Sstevel@tonic-gate     {
10377c478bd9Sstevel@tonic-gate 	printf (" Halfduplex\n");
10387c478bd9Sstevel@tonic-gate     }
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate     /* set MII 10 FULL ON */
10427c478bd9Sstevel@tonic-gate     WriteMII (17, 1, 1, ioaddr);
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate     /* turn on MII link change */
10457c478bd9Sstevel@tonic-gate     MIICRbak = inb (byMIICR);
10467c478bd9Sstevel@tonic-gate     outb (MIICRbak & 0x7F, byMIICR);
10477c478bd9Sstevel@tonic-gate     MIIDelay ();
10487c478bd9Sstevel@tonic-gate     outb (0x41, byMIIAD);
10497c478bd9Sstevel@tonic-gate     MIIDelay ();
10507c478bd9Sstevel@tonic-gate 
10517c478bd9Sstevel@tonic-gate     /* while((inb(byMIIAD)&0x20)==0) ; */
10527c478bd9Sstevel@tonic-gate     outb (MIICRbak | 0x80, byMIICR);
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate     nic->priv_data = &rhine;
10557c478bd9Sstevel@tonic-gate     tp = &rhine;
10567c478bd9Sstevel@tonic-gate     tp->chip_id = chip_id;
10577c478bd9Sstevel@tonic-gate     tp->ioaddr = ioaddr;
10587c478bd9Sstevel@tonic-gate     tp->phys[0] = -1;
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate     /* The lower four bits are the media type. */
10617c478bd9Sstevel@tonic-gate     if (options > 0)
10627c478bd9Sstevel@tonic-gate     {
10637c478bd9Sstevel@tonic-gate 	tp->full_duplex = (options & 16) ? 1 : 0;
10647c478bd9Sstevel@tonic-gate 	tp->default_port = options & 15;
10657c478bd9Sstevel@tonic-gate 	if (tp->default_port)
10667c478bd9Sstevel@tonic-gate 	    tp->medialock = 1;
10677c478bd9Sstevel@tonic-gate     }
10687c478bd9Sstevel@tonic-gate     return;
10697c478bd9Sstevel@tonic-gate }
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate static void
rhine_disable(struct dev * dev)10727c478bd9Sstevel@tonic-gate rhine_disable (struct dev *dev)
10737c478bd9Sstevel@tonic-gate {
10747c478bd9Sstevel@tonic-gate     struct nic *nic = (struct nic *)dev;
10757c478bd9Sstevel@tonic-gate     struct rhine_private *tp = (struct rhine_private *) nic->priv_data;
10767c478bd9Sstevel@tonic-gate     int ioaddr = tp->ioaddr;
10777c478bd9Sstevel@tonic-gate 
10787c478bd9Sstevel@tonic-gate     /* merge reset and disable */
10797c478bd9Sstevel@tonic-gate     rhine_reset(nic);
10807c478bd9Sstevel@tonic-gate 
10817c478bd9Sstevel@tonic-gate     printf ("rhine disable\n");
10827c478bd9Sstevel@tonic-gate     /* Switch to loopback mode to avoid hardware races. */
10837c478bd9Sstevel@tonic-gate     writeb(0x60 | 0x01, byTCR);
10847c478bd9Sstevel@tonic-gate     /* Stop the chip's Tx and Rx processes. */
10857c478bd9Sstevel@tonic-gate     writew(CR_STOP, byCR0);
10867c478bd9Sstevel@tonic-gate }
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate /**************************************************************************
10897c478bd9Sstevel@tonic-gate ETH_RESET - Reset adapter
10907c478bd9Sstevel@tonic-gate ***************************************************************************/
10917c478bd9Sstevel@tonic-gate static void
rhine_reset(struct nic * nic)10927c478bd9Sstevel@tonic-gate rhine_reset (struct nic *nic)
10937c478bd9Sstevel@tonic-gate {
10947c478bd9Sstevel@tonic-gate     struct rhine_private *tp = (struct rhine_private *) nic->priv_data;
10957c478bd9Sstevel@tonic-gate     int ioaddr = tp->ioaddr;
10967c478bd9Sstevel@tonic-gate     int i, j;
10977c478bd9Sstevel@tonic-gate     int FDXFlag, CRbak;
10987c478bd9Sstevel@tonic-gate     int rx_ring_tmp, rx_ring_tmp1;
10997c478bd9Sstevel@tonic-gate     int tx_ring_tmp, tx_ring_tmp1;
11007c478bd9Sstevel@tonic-gate     int rx_bufs_tmp, rx_bufs_tmp1;
11017c478bd9Sstevel@tonic-gate     int tx_bufs_tmp, tx_bufs_tmp1;
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate     static char buf1[RX_RING_SIZE * PKT_BUF_SZ + 32];
11047c478bd9Sstevel@tonic-gate     static char buf2[RX_RING_SIZE * PKT_BUF_SZ + 32];
11057c478bd9Sstevel@tonic-gate     static char desc1[TX_RING_SIZE * sizeof (struct rhine_tx_desc) + 32];
11067c478bd9Sstevel@tonic-gate     static char desc2[TX_RING_SIZE * sizeof (struct rhine_tx_desc) + 32];
11077c478bd9Sstevel@tonic-gate 
11087c478bd9Sstevel@tonic-gate     /* printf ("rhine_reset\n"); */
11097c478bd9Sstevel@tonic-gate     /* Soft reset the chip. */
11107c478bd9Sstevel@tonic-gate     /*outb(CmdReset, ioaddr + ChipCmd); */
11117c478bd9Sstevel@tonic-gate 
11127c478bd9Sstevel@tonic-gate     tx_bufs_tmp = (int) buf1;
11137c478bd9Sstevel@tonic-gate     tx_ring_tmp = (int) desc1;
11147c478bd9Sstevel@tonic-gate     rx_bufs_tmp = (int) buf2;
11157c478bd9Sstevel@tonic-gate     rx_ring_tmp = (int) desc2;
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate     /* tune RD TD 32 byte alignment */
11187c478bd9Sstevel@tonic-gate     rx_ring_tmp1 = (int) virt_to_bus ((char *) rx_ring_tmp);
11197c478bd9Sstevel@tonic-gate     j = (rx_ring_tmp1 + 32) & (~0x1f);
11207c478bd9Sstevel@tonic-gate     /* printf ("txring[%d]", j); */
11217c478bd9Sstevel@tonic-gate     tp->rx_ring = (struct rhine_rx_desc *) bus_to_virt (j);
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate     tx_ring_tmp1 = (int) virt_to_bus ((char *) tx_ring_tmp);
11247c478bd9Sstevel@tonic-gate     j = (tx_ring_tmp1 + 32) & (~0x1f);
11257c478bd9Sstevel@tonic-gate     tp->tx_ring = (struct rhine_tx_desc *) bus_to_virt (j);
11267c478bd9Sstevel@tonic-gate     /* printf ("rxring[%X]", j); */
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate     tx_bufs_tmp1 = (int) virt_to_bus ((char *) tx_bufs_tmp);
11307c478bd9Sstevel@tonic-gate     j = (int) (tx_bufs_tmp1 + 32) & (~0x1f);
11317c478bd9Sstevel@tonic-gate     tx_bufs_tmp = (int) bus_to_virt (j);
11327c478bd9Sstevel@tonic-gate     /* printf ("txb[%X]", j); */
11337c478bd9Sstevel@tonic-gate 
11347c478bd9Sstevel@tonic-gate     rx_bufs_tmp1 = (int) virt_to_bus ((char *) rx_bufs_tmp);
11357c478bd9Sstevel@tonic-gate     j = (int) (rx_bufs_tmp1 + 32) & (~0x1f);
11367c478bd9Sstevel@tonic-gate     rx_bufs_tmp = (int) bus_to_virt (j);
11377c478bd9Sstevel@tonic-gate     /* printf ("rxb[%X][%X]", rx_bufs_tmp1, j); */
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate     for (i = 0; i < RX_RING_SIZE; i++)
11407c478bd9Sstevel@tonic-gate     {
11417c478bd9Sstevel@tonic-gate 	tp->rx_buffs[i] = (char *) rx_bufs_tmp;
11427c478bd9Sstevel@tonic-gate 	/* printf("r[%X]",tp->rx_buffs[i]); */
11437c478bd9Sstevel@tonic-gate 	rx_bufs_tmp += 1536;
11447c478bd9Sstevel@tonic-gate     }
11457c478bd9Sstevel@tonic-gate 
11467c478bd9Sstevel@tonic-gate     for (i = 0; i < TX_RING_SIZE; i++)
11477c478bd9Sstevel@tonic-gate     {
11487c478bd9Sstevel@tonic-gate 	tp->tx_buffs[i] = (char *) tx_bufs_tmp;
11497c478bd9Sstevel@tonic-gate 	/* printf("t[%X]",tp->tx_buffs[i]);  */
11507c478bd9Sstevel@tonic-gate 	tx_bufs_tmp += 1536;
11517c478bd9Sstevel@tonic-gate     }
11527c478bd9Sstevel@tonic-gate 
11537c478bd9Sstevel@tonic-gate     /* software reset */
11547c478bd9Sstevel@tonic-gate     outb (CR1_SFRST, byCR1);
11557c478bd9Sstevel@tonic-gate     MIIDelay ();
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate     /* printf ("init ring"); */
11587c478bd9Sstevel@tonic-gate     rhine_init_ring (nic);
11597c478bd9Sstevel@tonic-gate     /*write TD RD Descriptor to MAC */
11607c478bd9Sstevel@tonic-gate     outl (virt_to_bus (tp->rx_ring), dwCurrentRxDescAddr);
11617c478bd9Sstevel@tonic-gate     outl (virt_to_bus (tp->tx_ring), dwCurrentTxDescAddr);
11627c478bd9Sstevel@tonic-gate 
11637c478bd9Sstevel@tonic-gate     /* Setup Multicast */
11647c478bd9Sstevel@tonic-gate     set_rx_mode(nic);
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate     /* close IMR */
11677c478bd9Sstevel@tonic-gate     outw (0x0000, byIMR0);
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate     /* set TCR RCR threshold */
11707c478bd9Sstevel@tonic-gate     outb (0x06, byBCR0);
11717c478bd9Sstevel@tonic-gate     outb (0x00, byBCR1);
11727c478bd9Sstevel@tonic-gate     outb (0x2c, byRCR);
11737c478bd9Sstevel@tonic-gate     outb (0x60, byTCR);
11747c478bd9Sstevel@tonic-gate     /* Set Fulldupex */
11757c478bd9Sstevel@tonic-gate     FDXFlag = QueryAuto (ioaddr);
11767c478bd9Sstevel@tonic-gate     if (FDXFlag == 1)
11777c478bd9Sstevel@tonic-gate     {
11787c478bd9Sstevel@tonic-gate 	outb (CFGD_CFDX, byCFGD);
11797c478bd9Sstevel@tonic-gate 	outw (CR_FDX, byCR0);
11807c478bd9Sstevel@tonic-gate     }
11817c478bd9Sstevel@tonic-gate 
11827c478bd9Sstevel@tonic-gate     /* KICK NIC to WORK */
11837c478bd9Sstevel@tonic-gate     CRbak = inw (byCR0);
11847c478bd9Sstevel@tonic-gate     CRbak = CRbak & 0xFFFB;	/* not CR_STOP */
11857c478bd9Sstevel@tonic-gate     outw ((CRbak | CR_STRT | CR_TXON | CR_RXON | CR_DPOLL), byCR0);
11867c478bd9Sstevel@tonic-gate 
11877c478bd9Sstevel@tonic-gate     /*set IMR to work */
11887c478bd9Sstevel@tonic-gate     outw (IMRShadow, byIMR0);
11897c478bd9Sstevel@tonic-gate }
11907c478bd9Sstevel@tonic-gate /* Beware of PCI posted writes */
11917c478bd9Sstevel@tonic-gate #define IOSYNC  do { readb(nic->ioaddr + StationAddr); } while (0)
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate static int
rhine_poll(struct nic * nic,int retreive)11947c478bd9Sstevel@tonic-gate rhine_poll (struct nic *nic, int retreive)
11957c478bd9Sstevel@tonic-gate {
11967c478bd9Sstevel@tonic-gate     struct rhine_private *tp = (struct rhine_private *) nic->priv_data;
11977c478bd9Sstevel@tonic-gate     int rxstatus, good = 0;;
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate     if (tp->rx_ring[tp->cur_rx].rx_status.bits.own_bit == 0)
12007c478bd9Sstevel@tonic-gate     {
12017c478bd9Sstevel@tonic-gate         unsigned int intr_status;
12027c478bd9Sstevel@tonic-gate         /* There is a packet ready */
12037c478bd9Sstevel@tonic-gate         if(!retreive)
12047c478bd9Sstevel@tonic-gate             return 1;
12057c478bd9Sstevel@tonic-gate 
12067c478bd9Sstevel@tonic-gate         intr_status = inw(nic->ioaddr + IntrStatus);
12077c478bd9Sstevel@tonic-gate         /* On Rhine-II, Bit 3 indicates Tx descriptor write-back race. */
12087c478bd9Sstevel@tonic-gate #if 0
12097c478bd9Sstevel@tonic-gate 	if (tp->chip_id == 0x3065)
12107c478bd9Sstevel@tonic-gate 	  intr_status |= inb(nic->ioaddr + IntrStatus2) << 16;
12117c478bd9Sstevel@tonic-gate #endif
12127c478bd9Sstevel@tonic-gate         /* Acknowledge all of the current interrupt sources ASAP. */
12137c478bd9Sstevel@tonic-gate         if (intr_status & IntrTxDescRace)
12147c478bd9Sstevel@tonic-gate            outb(0x08, nic->ioaddr + IntrStatus2);
12157c478bd9Sstevel@tonic-gate         outw(intr_status & 0xffff, nic->ioaddr + IntrStatus);
12167c478bd9Sstevel@tonic-gate 	IOSYNC;
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate 	rxstatus = tp->rx_ring[tp->cur_rx].rx_status.lw;
12197c478bd9Sstevel@tonic-gate 	if ((rxstatus & 0x0300) != 0x0300)
12207c478bd9Sstevel@tonic-gate 	{
12217c478bd9Sstevel@tonic-gate 	    printf("rhine_poll: bad status\n");
12227c478bd9Sstevel@tonic-gate 	}
12237c478bd9Sstevel@tonic-gate 	else if (rxstatus & (RSR_ABNORMAL))
12247c478bd9Sstevel@tonic-gate 	{
12257c478bd9Sstevel@tonic-gate 	    printf ("rxerr[%X]\n", rxstatus);
12267c478bd9Sstevel@tonic-gate 	}
12277c478bd9Sstevel@tonic-gate 	else
12287c478bd9Sstevel@tonic-gate 	    good = 1;
12297c478bd9Sstevel@tonic-gate 
12307c478bd9Sstevel@tonic-gate 	if (good)
12317c478bd9Sstevel@tonic-gate 	{
12327c478bd9Sstevel@tonic-gate 	    nic->packetlen = tp->rx_ring[tp->cur_rx].rx_status.bits.frame_length;
12337c478bd9Sstevel@tonic-gate 	    memcpy (nic->packet, tp->rx_buffs[tp->cur_rx], nic->packetlen);
12347c478bd9Sstevel@tonic-gate 	    /* printf ("Packet RXed\n"); */
12357c478bd9Sstevel@tonic-gate 	}
12367c478bd9Sstevel@tonic-gate 	tp->rx_ring[tp->cur_rx].rx_status.bits.own_bit = 1;
12377c478bd9Sstevel@tonic-gate 	tp->cur_rx++;
12387c478bd9Sstevel@tonic-gate 	tp->cur_rx = tp->cur_rx % RX_RING_SIZE;
12397c478bd9Sstevel@tonic-gate     }
12407c478bd9Sstevel@tonic-gate         /* Acknowledge all of the current interrupt sources ASAP. */
12417c478bd9Sstevel@tonic-gate         outw(DEFAULT_INTR & ~IntrRxDone, nic->ioaddr + IntrStatus);
12427c478bd9Sstevel@tonic-gate 
12437c478bd9Sstevel@tonic-gate         IOSYNC;
12447c478bd9Sstevel@tonic-gate 
12457c478bd9Sstevel@tonic-gate     return good;
12467c478bd9Sstevel@tonic-gate }
12477c478bd9Sstevel@tonic-gate 
12487c478bd9Sstevel@tonic-gate static void
rhine_transmit(struct nic * nic,const char * d,unsigned int t,unsigned int s,const char * p)12497c478bd9Sstevel@tonic-gate rhine_transmit (struct nic *nic,
12507c478bd9Sstevel@tonic-gate 		const char *d, unsigned int t, unsigned int s, const char *p)
12517c478bd9Sstevel@tonic-gate {
12527c478bd9Sstevel@tonic-gate     struct rhine_private *tp = (struct rhine_private *) nic->priv_data;
12537c478bd9Sstevel@tonic-gate     int ioaddr = tp->ioaddr;
12547c478bd9Sstevel@tonic-gate     int entry;
12557c478bd9Sstevel@tonic-gate     unsigned char CR1bak;
12567c478bd9Sstevel@tonic-gate 
12577c478bd9Sstevel@tonic-gate     /*printf ("rhine_transmit\n"); */
12587c478bd9Sstevel@tonic-gate     /* setup ethernet header */
12597c478bd9Sstevel@tonic-gate 
12607c478bd9Sstevel@tonic-gate 
12617c478bd9Sstevel@tonic-gate     /* Calculate the next Tx descriptor entry. */
12627c478bd9Sstevel@tonic-gate     entry = tp->cur_tx % TX_RING_SIZE;
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate     memcpy (tp->tx_buffs[entry], d, ETH_ALEN);	/* dst */
12657c478bd9Sstevel@tonic-gate     memcpy (tp->tx_buffs[entry] + ETH_ALEN, nic->node_addr, ETH_ALEN);	/* src */
12667c478bd9Sstevel@tonic-gate     *((char *) tp->tx_buffs[entry] + 12) = t >> 8;	/* type */
12677c478bd9Sstevel@tonic-gate     *((char *) tp->tx_buffs[entry] + 13) = t;
12687c478bd9Sstevel@tonic-gate     memcpy (tp->tx_buffs[entry] + ETH_HLEN, p, s);
12697c478bd9Sstevel@tonic-gate     s += ETH_HLEN;
12707c478bd9Sstevel@tonic-gate     while (s < ETH_ZLEN)
12717c478bd9Sstevel@tonic-gate 	*((char *) tp->tx_buffs[entry] + ETH_HLEN + (s++)) = 0;
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate     tp->tx_ring[entry].tx_ctrl.bits.tx_buf_size = s;
12747c478bd9Sstevel@tonic-gate 
12757c478bd9Sstevel@tonic-gate     tp->tx_ring[entry].tx_status.bits.own_bit = 1;
12767c478bd9Sstevel@tonic-gate 
12777c478bd9Sstevel@tonic-gate 
12787c478bd9Sstevel@tonic-gate     CR1bak = inb (byCR1);
12797c478bd9Sstevel@tonic-gate 
12807c478bd9Sstevel@tonic-gate     CR1bak = CR1bak | CR1_TDMD1;
12817c478bd9Sstevel@tonic-gate     /*printf("tdsw=[%X]",tp->tx_ring[entry].tx_status.lw); */
12827c478bd9Sstevel@tonic-gate     /*printf("tdcw=[%X]",tp->tx_ring[entry].tx_ctrl.lw); */
12837c478bd9Sstevel@tonic-gate     /*printf("tdbuf1=[%X]",tp->tx_ring[entry].buf_addr_1); */
12847c478bd9Sstevel@tonic-gate     /*printf("tdbuf2=[%X]",tp->tx_ring[entry].buf_addr_2); */
12857c478bd9Sstevel@tonic-gate     /*printf("td1=[%X]",inl(dwCurrentTDSE0)); */
12867c478bd9Sstevel@tonic-gate     /*printf("td2=[%X]",inl(dwCurrentTDSE1)); */
12877c478bd9Sstevel@tonic-gate     /*printf("td3=[%X]",inl(dwCurrentTDSE2)); */
12887c478bd9Sstevel@tonic-gate     /*printf("td4=[%X]",inl(dwCurrentTDSE3)); */
12897c478bd9Sstevel@tonic-gate 
12907c478bd9Sstevel@tonic-gate     outb (CR1bak, byCR1);
12917c478bd9Sstevel@tonic-gate     /* Wait until transmit is finished */
12927c478bd9Sstevel@tonic-gate     while (tp->tx_ring[entry].tx_status.bits.own_bit != 0)
12937c478bd9Sstevel@tonic-gate 	;
12947c478bd9Sstevel@tonic-gate     tp->cur_tx++;
12957c478bd9Sstevel@tonic-gate 
12967c478bd9Sstevel@tonic-gate     /*outw(IMRShadow,byIMR0); */
12977c478bd9Sstevel@tonic-gate     /*dev_kfree_skb(tp->tx_skbuff[entry], FREE_WRITE); */
12987c478bd9Sstevel@tonic-gate     /*tp->tx_skbuff[entry] = 0; */
12997c478bd9Sstevel@tonic-gate }
13007c478bd9Sstevel@tonic-gate 
13017c478bd9Sstevel@tonic-gate static struct pci_id rhine_nics[] = {
13027c478bd9Sstevel@tonic-gate PCI_ROM(0x1106, 0x3065, "dlink-530tx",     "VIA 6102"),
13037c478bd9Sstevel@tonic-gate PCI_ROM(0x1106, 0x3106, "via-rhine-6105",  "VIA 6105"),
13047c478bd9Sstevel@tonic-gate PCI_ROM(0x1106, 0x3043, "dlink-530tx-old", "VIA 3043"),		/* Rhine-I 86c100a */
13057c478bd9Sstevel@tonic-gate PCI_ROM(0x1106, 0x3053, "via6105m",        "VIA 6105M"),
13067c478bd9Sstevel@tonic-gate PCI_ROM(0x1106, 0x6100, "via-rhine-old",   "VIA 86C100A"),	/* Rhine-II */
13077c478bd9Sstevel@tonic-gate };
13087c478bd9Sstevel@tonic-gate 
13097c478bd9Sstevel@tonic-gate struct pci_driver rhine_driver = {
13107c478bd9Sstevel@tonic-gate 	.type     = NIC_DRIVER,
13117c478bd9Sstevel@tonic-gate 	.name     = "VIA 86C100",
13127c478bd9Sstevel@tonic-gate 	.probe    = rhine_probe,
13137c478bd9Sstevel@tonic-gate 	.ids      = rhine_nics,
13147c478bd9Sstevel@tonic-gate 	.id_count = sizeof(rhine_nics)/sizeof(rhine_nics[0]),
13157c478bd9Sstevel@tonic-gate 	.class    = 0,
13167c478bd9Sstevel@tonic-gate };
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate /* EOF via-rhine.c */
1319