xref: /plan9/sys/src/9/pc/ethervgbe.c (revision 6083aa4307383671473908ab2d661f80fbf6814b)
1a9604be0SDavid du Colombier /*
2a9604be0SDavid du Colombier  * VIA Velocity gigabit ethernet.
3a9604be0SDavid du Colombier  * Register info has been stolen from FreeBSD driver.
4a9604be0SDavid du Colombier  *
5a9604be0SDavid du Colombier  * Has been tested on:
6a9604be0SDavid du Colombier  *	- VIA8237 (ABIT AV8): 100Mpbs Full duplex only.
7a9604be0SDavid du Colombier  *	  It works enough to run replica/pull, vncv, ...
8a9604be0SDavid du Colombier  *
9a9604be0SDavid du Colombier  * To do:
10a9604be0SDavid du Colombier  *	- 64/48 bits
11a9604be0SDavid du Colombier  *	- autonegotiation
12a9604be0SDavid du Colombier  *	- thresholds
13a9604be0SDavid du Colombier  *	- dynamic ring sizing ??
14a9604be0SDavid du Colombier  *	- link status change
15e183b1a6SDavid du Colombier  *	- shutdown
16a9604be0SDavid du Colombier  *	- promiscuous
17a9604be0SDavid du Colombier  *	- report error
18a9604be0SDavid du Colombier  *	- Rx/Tx Csum
19a9604be0SDavid du Colombier  *	- Jumbo frames
20a9604be0SDavid du Colombier  *
21a9604be0SDavid du Colombier  * Philippe Anel, xigh@free.fr
22a9604be0SDavid du Colombier  */
23a9604be0SDavid du Colombier 
24a9604be0SDavid du Colombier #include "u.h"
25a9604be0SDavid du Colombier #include "../port/lib.h"
26a9604be0SDavid du Colombier #include "mem.h"
27a9604be0SDavid du Colombier #include "dat.h"
28a9604be0SDavid du Colombier #include "fns.h"
29a9604be0SDavid du Colombier #include "io.h"
30a9604be0SDavid du Colombier #include "../port/error.h"
31a9604be0SDavid du Colombier #include "../port/netif.h"
32a9604be0SDavid du Colombier 
33a9604be0SDavid du Colombier #include "etherif.h"
34a9604be0SDavid du Colombier #include "ethermii.h"
35a9604be0SDavid du Colombier 
36a9604be0SDavid du Colombier #define DEBUG
37a9604be0SDavid du Colombier 
38a9604be0SDavid du Colombier enum
39a9604be0SDavid du Colombier {
40a9604be0SDavid du Colombier 	DumpIntr	= (1<<0),
41a9604be0SDavid du Colombier 	DumpRx		= (1<<1),
42a9604be0SDavid du Colombier 	DumpTx		= (1<<2),
43a9604be0SDavid du Colombier };
44a9604be0SDavid du Colombier 
45a9604be0SDavid du Colombier #define htole16(x) (x)
46a9604be0SDavid du Colombier #define htole32(x) (x)
47a9604be0SDavid du Colombier #define le32toh(x) (x)
48a9604be0SDavid du Colombier 
49a9604be0SDavid du Colombier enum
50a9604be0SDavid du Colombier {
51a9604be0SDavid du Colombier 	Timeout		= 50000,
52a9604be0SDavid du Colombier 	RxCount		= 256,
53a9604be0SDavid du Colombier 	TxCount		= 256,
54a9604be0SDavid du Colombier 	RxSize		= 2048,
55a9604be0SDavid du Colombier 
56a9604be0SDavid du Colombier 	EthAddr		= 0x00,
57a9604be0SDavid du Colombier 
58a9604be0SDavid du Colombier 	/* Command registers. */
59a9604be0SDavid du Colombier 	Cr0S		= 0x08,			/* Global command 0 (Set) */
60a9604be0SDavid du Colombier 	Cr0C		= 0x0c,			/* Global command 0 (Clear) */
61a9604be0SDavid du Colombier 		Cr0_Start	= 0x01,		/* - start MAC */
62a9604be0SDavid du Colombier 		Cr0_Stop	= 0x02,		/* - stop MAC */
63a9604be0SDavid du Colombier 		Cr0_EnableRx	= 0x04,		/* - turn on Rx engine */
64a9604be0SDavid du Colombier 		Cr0_EnableTx	= 0x08,		/* - turn on Tx engine */
65a9604be0SDavid du Colombier 
66a9604be0SDavid du Colombier 	Cr1S		= 0x09,			/* Global command 1 (Set) */
67a9604be0SDavid du Colombier 	Cr1C		= 0x0d,			/* Global command 1 (Clear) */
68a9604be0SDavid du Colombier 		Cr1_NoPool	= 0x08,		/* - disable Rx/Tx desc pool */
69a9604be0SDavid du Colombier 		Cr1_reset	= 0x80,		/* - software reset */
70a9604be0SDavid du Colombier 
71a9604be0SDavid du Colombier 	Cr2S		= 0x0a,			/* Global command 2 (Set) */
72a9604be0SDavid du Colombier 		Cr2_XonEnable	= 0x80,		/* - 802.3x XON/XOFF flow control */
73a9604be0SDavid du Colombier 
74a9604be0SDavid du Colombier 	Cr3S		= 0x0b,			/* Global command 3 (Set) */
75a9604be0SDavid du Colombier 	Cr3C		= 0x0f,			/* Global command 3 (Set) */
76a9604be0SDavid du Colombier 		Cr3_IntMask	= 0x02,		/* - Mask all interrupts */
77a9604be0SDavid du Colombier 
78a9604be0SDavid du Colombier 	/* Eeprom registers. */
79a9604be0SDavid du Colombier 	Eecsr		= 0x93,			/* EEPROM control/status */
80a9604be0SDavid du Colombier 		Eecsr_Autold	= 0x20,		/* - trigger reload from EEPROM */
81a9604be0SDavid du Colombier 
82a9604be0SDavid du Colombier 	/* Mii registers. */
83a9604be0SDavid du Colombier 	MiiStatus	= 0x6D,			/* MII port status */
84a9604be0SDavid du Colombier 		MiiStatus_idle	= 0x80,		/* - idle */
85a9604be0SDavid du Colombier 
86a9604be0SDavid du Colombier 	MiiCmd		= 0x70,			/* MII command */
87a9604be0SDavid du Colombier 		MiiCmd_write	= 0x20,		/* - write */
88a9604be0SDavid du Colombier 		MiiCmd_read	= 0x40,		/* - read */
89a9604be0SDavid du Colombier 		MiiCmd_auto	= 0x80,		/* - enable autopolling */
90a9604be0SDavid du Colombier 
91a9604be0SDavid du Colombier 	MiiAddr		= 0x71,			/* MII address */
92a9604be0SDavid du Colombier 	MiiData		= 0x72,			/* MII data */
93a9604be0SDavid du Colombier 
94a9604be0SDavid du Colombier 	/* 64 bits related registers. */
95a9604be0SDavid du Colombier 	TxDescHi	= 0x18,
96a9604be0SDavid du Colombier 	DataBufHi	= 0x1d,
97a9604be0SDavid du Colombier 
98a9604be0SDavid du Colombier 	/* Rx engine registers. */
99a9604be0SDavid du Colombier 	RxDescLo	= 0x38,			/* Rx descriptor base address (lo 32 bits) */
100a9604be0SDavid du Colombier 	RxCsrS		= 0x32,			/* Rx descriptor queue control/status (Set) */
101a9604be0SDavid du Colombier 	RxCsrC		= 0x36,			/* Rx descriptor queue control/status (Clear) */
102a9604be0SDavid du Colombier 		RxCsr_RunQueue	= 0x01,		/* 	- enable queue */
103a9604be0SDavid du Colombier 		RxCsr_Active	= 0x02,		/* - queue active indicator */
104a9604be0SDavid du Colombier 		RxCsr_Wakeup	= 0x04,		/* - wake up queue */
105a9604be0SDavid du Colombier 		RxCsr_Dead	= 0x08,		/* - queue dead indicator */
106a9604be0SDavid du Colombier 	RxNum		= 0x50,			/* Size of Rx desc ring */
107a9604be0SDavid du Colombier 	RxDscIdx	= 0x3c,			/* Current Rx descriptor index */
108a9604be0SDavid du Colombier 	RxResCnt	= 0x5e,			/* Rx descriptor residue count */
109a9604be0SDavid du Colombier 	RxHostErr	= 0x23,			/* Rx host error status */
110a9604be0SDavid du Colombier 	RxTimer		= 0x3e,			/* Rx queue timer pend */
111a9604be0SDavid du Colombier 	RxControl	= 0x06,			/* MAC Rx control */
112a9604be0SDavid du Colombier 		RxControl_BadFrame = 0x01,	/* - accept CRC error frames */
113a9604be0SDavid du Colombier 		RxControl_Runt = 0x02,		/* - accept runts */
114a9604be0SDavid du Colombier 		RxControl_MultiCast = 0x04,	/* - accept multicasts */
115a9604be0SDavid du Colombier 		RxControl_BroadCast = 0x08,	/* - accept broadcasts */
116a9604be0SDavid du Colombier 		RxControl_Promisc = 0x10,	/* - promisc mode */
117a9604be0SDavid du Colombier 		RxControl_Giant = 0x20,		/* - accept VLAN tagged frames */
118a9604be0SDavid du Colombier 		RxControl_UniCast = 0x40,	/* - use perfect filtering */
119a9604be0SDavid du Colombier 		RxControl_SymbolErr = 0x80,	/* - accept symbol err packet */
120a9604be0SDavid du Colombier 	RxConfig	= 0x7e,			/* MAC Rx config */
121a9604be0SDavid du Colombier 		RxConfig_VlanFilter = 0x01,	/* - filter VLAN ID mismatches */
122a9604be0SDavid du Colombier 		RxConfig_VlanOpt0 = (0<<1),	/* - TX: no tag insert, RX: all, no extr */
123a9604be0SDavid du Colombier 		RxConfig_VlanOpt1 = (1<<1),	/* - TX: no tag insert, RX: tagged pkts, no extr */
124a9604be0SDavid du Colombier 		RxConfig_VlanOpt2 = (2<<1),	/* - TX: tag insert, RX: all, extract tags */
125a9604be0SDavid du Colombier 		RxConfig_VlanOpt3 = (3<<1),	/* - TX: tag insert, RX: tagged pkts, with extr */
126a9604be0SDavid du Colombier 		RxConfig_FifoLowWat = 0x08,	/* - RX FIFO low watermark (7QW/15QW) */
127a9604be0SDavid du Colombier 		RxConfig_FifoTh128 = (0<<4),	/* - RX FIFO threshold 128 bytes */
128a9604be0SDavid du Colombier 		RxConfig_FifoTh512 = (1<<4),	/* - RX FIFO threshold 512 bytes */
129a9604be0SDavid du Colombier 		RxConfig_FifoTh1024 = (2<<4),	/* - RX FIFO threshold 1024 bytes */
130a9604be0SDavid du Colombier 		RxConfig_FifoThFwd = (3<<4),	/* - RX FIFO threshold ??? */
131a9604be0SDavid du Colombier 		RxConfig_ArbPrio = 0x80,	/* - arbitration priority */
132a9604be0SDavid du Colombier 
133a9604be0SDavid du Colombier 	/* Tx engine registers. */
134a9604be0SDavid du Colombier 	TxDescLo	= 0x40,			/* Tx descriptor base address (lo 32 bits) */
135a9604be0SDavid du Colombier 	TxCsrS		= 0x30,			/* Tx descriptor queue control/status (Set) */
136a9604be0SDavid du Colombier 	TxCsrC		= 0x38,			/* Tx descriptor queue control/status (Clear) */
137a9604be0SDavid du Colombier 		TxCsr_RunQueue	= 0x01,		/* 	- enable queue */
138a9604be0SDavid du Colombier 		TxCsr_Active	= 0x02,		/* - queue active indicator */
139a9604be0SDavid du Colombier 		TxCsr_Wakeup	= 0x04,		/* - wake up queue */
140a9604be0SDavid du Colombier 		TxCsr_Dead	= 0x08,		/* - queue dead indicator */
141a9604be0SDavid du Colombier 	TxNum		= 0x52,			/* Size of Tx desc ring */
142a9604be0SDavid du Colombier 	TxDscIdx	= 0x54,			/* Current Tx descriptor index */
143a9604be0SDavid du Colombier 	TxHostErr	= 0x22,			/* Tx host error status */
144a9604be0SDavid du Colombier 	TxTimer		= 0x3f,			/* Tx queue timer pend */
145a9604be0SDavid du Colombier 	TxControl	= 0x07,			/* MAC Rx control */
146a9604be0SDavid du Colombier 		TxControl_LC_Off = (0<<0),	/* - loopback control off */
147a9604be0SDavid du Colombier 		TxControl_LC_Mac = (1<<0),	/* - loopback control MAC internal */
148a9604be0SDavid du Colombier 		TxControl_LC_Ext = (2<<0),	/* - loopback control external */
149a9604be0SDavid du Colombier 		TxControl_Coll16 = (0<<2),	/* - one set of 16 retries */
150a9604be0SDavid du Colombier 		TxControl_Coll32 = (1<<2),	/* - two sets of 16 retries */
151a9604be0SDavid du Colombier 		TxControl_Coll48 = (2<<2),	/* - three sets of 16 retries */
152a9604be0SDavid du Colombier 		TxControl_CollInf = (3<<2),	/* - retry forever */
153a9604be0SDavid du Colombier 
154a9604be0SDavid du Colombier 	TxConfig	= 0x7f,			/* MAC Tx config */
155a9604be0SDavid du Colombier 		TxConfig_SnapOpt = 0x01,	/* - 1 == insert VLAN tag at 13th byte, */
156a9604be0SDavid du Colombier 										/*	  0 == insert VLAN tag after SNAP header (21st byte) */
157a9604be0SDavid du Colombier 		TxConfig_NonBlk	= 0x02,		/* - priority TX/non-blocking mode */
158a9604be0SDavid du Colombier 		TxConfig_Blk64	= (0<<3),	/* - non-blocking threshold 64 packets */
159a9604be0SDavid du Colombier 		TxConfig_Blk32	= (1<<3),	/* - non-blocking threshold 32 packets */
160a9604be0SDavid du Colombier 		TxConfig_Blk128	= (2<<3),	/* - non-blocking threshold 128 packets */
161a9604be0SDavid du Colombier 		TxConfig_Blk8	= (3<<3),	/* - non-blocking threshold 8 packets */
162a9604be0SDavid du Colombier 		TxConfig_ArbPrio	= 0x80,	/* - arbitration priority */
163a9604be0SDavid du Colombier 
164a9604be0SDavid du Colombier 	/* Timer registers. */
165a9604be0SDavid du Colombier 	Timer0		= 0x74,			/* single-shot timer */
166a9604be0SDavid du Colombier 	Timer1		= 0x76,			/* periodic timer */
167a9604be0SDavid du Colombier 
168a9604be0SDavid du Colombier 	/* Chip config registers. */
169a9604be0SDavid du Colombier 	ChipCfgA	= 0x78,			/* chip config A */
170a9604be0SDavid du Colombier 	ChipCfgB	= 0x79,			/* chip config B */
171a9604be0SDavid du Colombier 	ChipCfgC	= 0x7a,			/* chip config C */
172a9604be0SDavid du Colombier 	ChipCfgD	= 0x7b,			/* chip config D */
173a9604be0SDavid du Colombier 
174a9604be0SDavid du Colombier 	/* DMA config registers. */
175a9604be0SDavid du Colombier 	DmaCfg0		= 0x7C,			/* DMA config 0 */
176a9604be0SDavid du Colombier 	DmaCfg1		= 0x7D,			/* DMA config 1 */
177a9604be0SDavid du Colombier 
178a9604be0SDavid du Colombier 	/* Interrupt registers. */
179a9604be0SDavid du Colombier 	IntCtl		= 0x20,			/* Interrupt control */
180a9604be0SDavid du Colombier 	Imr		= 0x28,			/* Interrupt mask */
181a9604be0SDavid du Colombier 	Isr		= 0x24,			/* Interrupt status */
182a9604be0SDavid du Colombier 		Isr_RxHiPrio	= (1<<0),	/* - hi prio Rx int */
183a9604be0SDavid du Colombier 		Isr_TxHiPrio	= (1<<1),	/* - hi prio Tx int */
184a9604be0SDavid du Colombier 		Isr_RxComplete	= (1<<2),	/* - Rx queue completed */
185a9604be0SDavid du Colombier 		Isr_TxComplete	= (1<<3),	/* - One of Tx queues completed */
186a9604be0SDavid du Colombier 
187a9604be0SDavid du Colombier 		Isr_TxComplete0	= (1<<4),	/* - Tx queue 0 completed */
188a9604be0SDavid du Colombier 		Isr_TxComplete1	= (1<<5),	/* - Tx queue 1 completed */
189a9604be0SDavid du Colombier 		Isr_TxComplete2	= (1<<6),	/* - Tx queue 2 completed */
190a9604be0SDavid du Colombier 		Isr_TxComplete3	= (1<<7),	/* - Tx queue 3 completed */
191a9604be0SDavid du Colombier 
192a9604be0SDavid du Colombier 		Isr_Reserved8	= (1<<8),	/* - reserved */
193a9604be0SDavid du Colombier 		Isr_Reserver9	= (1<<9),	/* - reserved */
194a9604be0SDavid du Colombier 		Isr_RxCountOvflow = (1<<10),	/* - Rx packet count overflow */
195a9604be0SDavid du Colombier 		Isr_RxPause	= (1<<11),	/* - pause frame Rx */
196a9604be0SDavid du Colombier 
197a9604be0SDavid du Colombier 		Isr_RxFifoOvflow = (1<<12),	/* - RX FIFO overflow */
198a9604be0SDavid du Colombier 		Isr_RxNoDesc	= (1<<13),	/* - ran out of Rx descriptors */
199a9604be0SDavid du Colombier 		Isr_RxNoDescWar	= (1<<14),	/* - running out of Rx descriptors */
200a9604be0SDavid du Colombier 		Isr_LinkStatus	= (1<<15),	/* - link status change */
201a9604be0SDavid du Colombier 
202a9604be0SDavid du Colombier 		Isr_Timer0	= (1<<16),	/* - one shot timer expired */
203a9604be0SDavid du Colombier 		Isr_Timer1	= (1<<17),	/* - periodic timer expired */
204a9604be0SDavid du Colombier 		Isr_Power	= (1<<18),	/* - wake up power event */
205a9604be0SDavid du Colombier 		Isr_PhyIntr	= (1<<19),	/* - PHY interrupt */
206a9604be0SDavid du Colombier 
207a9604be0SDavid du Colombier 		Isr_Stopped	= (1<<20),	/* - software shutdown complete */
208a9604be0SDavid du Colombier 		Isr_MibOvflow	= (1<<21),	/* - MIB counter overflow warning */
209a9604be0SDavid du Colombier 		Isr_SoftIntr	= (1<<22),	/* - software interrupt */
210a9604be0SDavid du Colombier 		Isr_HoldOffReload = (1<<23),	/* - reload hold timer */
211a9604be0SDavid du Colombier 
212a9604be0SDavid du Colombier 		Isr_RxDmaStall	= (1<<24),	/* - Rx DMA stall */
213a9604be0SDavid du Colombier 		Isr_TxDmaStall	= (1<<25),	/* - Tx DMA stall */
214a9604be0SDavid du Colombier 		Isr_Reserved26	= (1<<26),	/* - reserved */
215a9604be0SDavid du Colombier 		Isr_Reserved27	= (1<<27),	/* - reserved */
216a9604be0SDavid du Colombier 
217a9604be0SDavid du Colombier 		Isr_Source0	= (1<<28),	/* - interrupt source indication */
218a9604be0SDavid du Colombier 		Isr_Source1	= (1<<29),	/* - interrupt source indication */
219a9604be0SDavid du Colombier 		Isr_Source2	= (1<<30),	/* - interrupt source indication */
220a9604be0SDavid du Colombier 		Isr_Source3	= (1<<31),	/* - interrupt source indication */
221a9604be0SDavid du Colombier 
222a9604be0SDavid du Colombier 	Isr_Mask = Isr_TxComplete0|Isr_RxComplete|Isr_Stopped|
223a9604be0SDavid du Colombier 			Isr_RxFifoOvflow|Isr_PhyIntr|Isr_LinkStatus|
224a9604be0SDavid du Colombier 			Isr_RxNoDesc|Isr_RxDmaStall|Isr_TxDmaStall
225a9604be0SDavid du Colombier };
226a9604be0SDavid du Colombier 
227a9604be0SDavid du Colombier typedef struct Frag Frag;
228a9604be0SDavid du Colombier struct Frag
229a9604be0SDavid du Colombier {
230a9604be0SDavid du Colombier 	ulong	addr_lo;
231a9604be0SDavid du Colombier 	ushort	addr_hi;
232a9604be0SDavid du Colombier 	ushort	length;
233a9604be0SDavid du Colombier };
234a9604be0SDavid du Colombier 
235a9604be0SDavid du Colombier typedef struct RxDesc RxDesc;
236a9604be0SDavid du Colombier struct RxDesc
237a9604be0SDavid du Colombier {
238a9604be0SDavid du Colombier 	ulong	status;
239a9604be0SDavid du Colombier 	ulong	control;
240a9604be0SDavid du Colombier 	Frag;
241a9604be0SDavid du Colombier };
242a9604be0SDavid du Colombier 
243a9604be0SDavid du Colombier typedef struct TxDesc TxDesc;
244a9604be0SDavid du Colombier struct TxDesc
245a9604be0SDavid du Colombier {
246a9604be0SDavid du Colombier 	ulong	status;
247a9604be0SDavid du Colombier 	ulong	control;
248a9604be0SDavid du Colombier 	Frag	frags[7];
249a9604be0SDavid du Colombier };
250a9604be0SDavid du Colombier 
251a9604be0SDavid du Colombier enum
252a9604be0SDavid du Colombier {
253a9604be0SDavid du Colombier 	RxDesc_Status_VidMiss	= (1<<0),	/* VLAN tag filter miss */
254a9604be0SDavid du Colombier 	RxDesc_Status_CrcErr	= (1<<1),	/* bad CRC error */
255a9604be0SDavid du Colombier 	RxDesc_Status_FrAlErr	= (1<<3),	/* frame alignment error */
256a9604be0SDavid du Colombier 	RxDesc_Status_CsumErr	= (1<<3),	/* bad TCP/IP checksum */
257a9604be0SDavid du Colombier 	RxDesc_Status_RxLenErr	= (1<<4),	/* Rx length error */
258a9604be0SDavid du Colombier 	RxDesc_Status_SymErr	= (1<<5),	/* PCS symbol error */
259a9604be0SDavid du Colombier 	RxDesc_Status_SnTag	= (1<<6),	/* RX'ed tagged SNAP pkt */
260a9604be0SDavid du Colombier 	RxDesc_Status_DeTag	= (1<<7),	/* VLAN tag extracted */
261a9604be0SDavid du Colombier 
262a9604be0SDavid du Colombier 	RxDesc_Status_OneFrag	= (0<<8),	/* only one fragment */
263a9604be0SDavid du Colombier 	RxDesc_Status_FirstFrag	= (1<<8),	/* first frag in frame */
264a9604be0SDavid du Colombier 	RxDesc_Status_LastFrag	= (2<<8),	/* last frag in frame */
265a9604be0SDavid du Colombier 	RxDesc_Status_MidFrag	= (3<<8),	/* intermediate frag */
266a9604be0SDavid du Colombier 
267a9604be0SDavid du Colombier 	RxDesc_Status_Vtag	= (1<<10),	/* VLAN tag indicator */
268a9604be0SDavid du Colombier 	RxDesc_Status_UniCast	= (1<<11),	/* unicast frame */
269a9604be0SDavid du Colombier 	RxDesc_Status_BroadCast	= (1<<12),	/* broadcast frame */
270a9604be0SDavid du Colombier 	RxDesc_Status_MultiCast	= (1<<13),	/* multicast frame */
271a9604be0SDavid du Colombier 	RxDesc_Status_Perfect	= (1<<14),	/* perfect filter hit */
272a9604be0SDavid du Colombier 	RxDesc_Status_Goodframe	= (1<<15),	/* frame is good. */
273a9604be0SDavid du Colombier 
274a9604be0SDavid du Colombier 	RxDesc_Status_SizShift	= 16,		/* received frame len shift */
275a9604be0SDavid du Colombier 	RxDesc_Status_SizMask	= 0x3FFF,	/* received frame len mask */
276a9604be0SDavid du Colombier 
277a9604be0SDavid du Colombier 	RxDesc_Status_Shutdown	= (1<<30),	/* shutdown during RX */
278a9604be0SDavid du Colombier 	RxDesc_Status_Own	= (1<<31),	/* own bit */
279a9604be0SDavid du Colombier 
280a9604be0SDavid du Colombier 	/* ... */
281a9604be0SDavid du Colombier 	TxDesc_Status_Own	= (1<<31),	/* own bit */
282a9604be0SDavid du Colombier 
283a9604be0SDavid du Colombier 	/* ... */
284a9604be0SDavid du Colombier 	TxDesc_Control_Intr	= (1<<23),	/* Tx intr request */
285a9604be0SDavid du Colombier 	TxDesc_Control_Normal	= (3<<24),	/* normal frame */
286a9604be0SDavid du Colombier };
287a9604be0SDavid du Colombier 
288a9604be0SDavid du Colombier typedef struct Stats Stats;
289a9604be0SDavid du Colombier struct Stats
290a9604be0SDavid du Colombier {
291a9604be0SDavid du Colombier 	ulong	rx;
292a9604be0SDavid du Colombier 	ulong	tx;
293a9604be0SDavid du Colombier 	ulong	txe;
294a9604be0SDavid du Colombier 	ulong	intr;
295a9604be0SDavid du Colombier };
296a9604be0SDavid du Colombier 
297a9604be0SDavid du Colombier typedef struct Ctlr Ctlr;
298a9604be0SDavid du Colombier struct Ctlr
299a9604be0SDavid du Colombier {
300a9604be0SDavid du Colombier 	Ctlr*	link;
301a9604be0SDavid du Colombier 	Pcidev*	pdev;
302a9604be0SDavid du Colombier 	int	port;
303a9604be0SDavid du Colombier 
304a9604be0SDavid du Colombier 	int	inited;
305a9604be0SDavid du Colombier 	Lock	init_lock;
306a9604be0SDavid du Colombier 
307a9604be0SDavid du Colombier 	ulong	debugflags;
308a9604be0SDavid du Colombier 	ulong	debugcount;
309a9604be0SDavid du Colombier 
310a9604be0SDavid du Colombier 	Mii*	mii;
311a9604be0SDavid du Colombier 	int	active;
312a9604be0SDavid du Colombier 	uchar	ea[6];
313a9604be0SDavid du Colombier 
314a9604be0SDavid du Colombier 	RxDesc*	rx_ring;
315a9604be0SDavid du Colombier 	Block*	rx_blocks[RxCount];
316a9604be0SDavid du Colombier 
317a9604be0SDavid du Colombier 	Lock	tx_lock;
318a9604be0SDavid du Colombier 	TxDesc*	tx_ring;
319a9604be0SDavid du Colombier 	Block*	tx_blocks[TxCount];
320a9604be0SDavid du Colombier 	ulong	tx_count;
321a9604be0SDavid du Colombier 
322a9604be0SDavid du Colombier 	Stats	stats;
323a9604be0SDavid du Colombier };
324a9604be0SDavid du Colombier 
325a9604be0SDavid du Colombier static Ctlr* vgbehead;
326a9604be0SDavid du Colombier static Ctlr* vgbetail;
327a9604be0SDavid du Colombier 
328a9604be0SDavid du Colombier #define riob(c, r)	inb(c->port + r)
329a9604be0SDavid du Colombier #define riow(c, r)	ins(c->port + r)
330a9604be0SDavid du Colombier #define riol(c, r)	inl(c->port + r)
331a9604be0SDavid du Colombier #define wiob(c, r, d)	outb(c->port + r, d)
332a9604be0SDavid du Colombier #define wiow(c, r, d)	outs(c->port + r, d)
333a9604be0SDavid du Colombier #define wiol(c, r, d)	outl(c->port + r, d)
334a9604be0SDavid du Colombier 
335a9604be0SDavid du Colombier #define siob(c, r, b)	wiob(c, r, riob(c, r) | b)
336a9604be0SDavid du Colombier #define siow(c, r, b)	wiow(c, r, riob(c, r) | b)
337a9604be0SDavid du Colombier #define siol(c, r, b)	wiol(c, r, riob(c, r) | b)
338a9604be0SDavid du Colombier #define ciob(c, r, b)	wiob(c, r, riob(c, r) & ~b)
339a9604be0SDavid du Colombier #define ciow(c, r, b)	wiow(c, r, riob(c, r) & ~b)
340a9604be0SDavid du Colombier #define ciol(c, r, b)	wiol(c, r, riob(c, r) & ~b)
341a9604be0SDavid du Colombier 
342a9604be0SDavid du Colombier static int
vgbemiiw(Mii * mii,int phy,int addr,int data)343a9604be0SDavid du Colombier vgbemiiw(Mii* mii, int phy, int addr, int data)
344a9604be0SDavid du Colombier {
345a9604be0SDavid du Colombier 	Ctlr* ctlr;
346a9604be0SDavid du Colombier 	int i;
347a9604be0SDavid du Colombier 
348a9604be0SDavid du Colombier 	if(phy != 1)
349a9604be0SDavid du Colombier 		return -1;
350a9604be0SDavid du Colombier 
351a9604be0SDavid du Colombier 	ctlr = mii->ctlr;
352a9604be0SDavid du Colombier 
353a9604be0SDavid du Colombier 	wiob(ctlr, MiiAddr, addr);
354a9604be0SDavid du Colombier 	wiow(ctlr, MiiData, (ushort) data);
355a9604be0SDavid du Colombier 	wiob(ctlr, MiiCmd, MiiCmd_write);
356a9604be0SDavid du Colombier 
357a9604be0SDavid du Colombier 	for(i = 0; i < Timeout; i++)
358a9604be0SDavid du Colombier 		if((riob(ctlr, MiiCmd) & MiiCmd_write) == 0)
359a9604be0SDavid du Colombier 			break;
360a9604be0SDavid du Colombier 
361a9604be0SDavid du Colombier 	if(i >= Timeout){
362a9604be0SDavid du Colombier 		print("vgbe: miiw timeout\n");
363a9604be0SDavid du Colombier 		return -1;
364a9604be0SDavid du Colombier 	}
365a9604be0SDavid du Colombier 
366a9604be0SDavid du Colombier 	return 0;
367a9604be0SDavid du Colombier }
368a9604be0SDavid du Colombier 
369a9604be0SDavid du Colombier static int
vgbemiir(Mii * mii,int phy,int addr)370a9604be0SDavid du Colombier vgbemiir(Mii* mii, int phy, int addr)
371a9604be0SDavid du Colombier {
372a9604be0SDavid du Colombier 	Ctlr* ctlr;
373a9604be0SDavid du Colombier 	int i;
374a9604be0SDavid du Colombier 
375a9604be0SDavid du Colombier 	if(phy != 1)
376a9604be0SDavid du Colombier 		return -1;
377a9604be0SDavid du Colombier 
378a9604be0SDavid du Colombier 	ctlr = mii->ctlr;
379a9604be0SDavid du Colombier 
380a9604be0SDavid du Colombier 	wiob(ctlr, MiiAddr, addr);
381a9604be0SDavid du Colombier 	wiob(ctlr, MiiCmd, MiiCmd_read);
382a9604be0SDavid du Colombier 
383a9604be0SDavid du Colombier 	for(i = 0; i < Timeout; i++)
384a9604be0SDavid du Colombier 		if((riob(ctlr, MiiCmd) & MiiCmd_read) == 0)
385a9604be0SDavid du Colombier 			break;
386a9604be0SDavid du Colombier 
387a9604be0SDavid du Colombier 	if(i >= Timeout){
388a9604be0SDavid du Colombier 		print("vgbe: miir timeout\n");
389a9604be0SDavid du Colombier 		return -1;
390a9604be0SDavid du Colombier 	}
391a9604be0SDavid du Colombier 
392a9604be0SDavid du Colombier 	return riow(ctlr, MiiData);
393a9604be0SDavid du Colombier }
394a9604be0SDavid du Colombier 
395a9604be0SDavid du Colombier static long
vgbeifstat(Ether * edev,void * a,long n,ulong offset)396a9604be0SDavid du Colombier vgbeifstat(Ether* edev, void* a, long n, ulong offset)
397a9604be0SDavid du Colombier {
398a9604be0SDavid du Colombier 	char* p;
399a9604be0SDavid du Colombier 	Ctlr* ctlr;
400a9604be0SDavid du Colombier 	int l;
401a9604be0SDavid du Colombier 
402a9604be0SDavid du Colombier 	ctlr = edev->ctlr;
403a9604be0SDavid du Colombier 
40446136019SDavid du Colombier 	p = malloc(READSTR);
405aa72973aSDavid du Colombier 	if(p == nil)
406aa72973aSDavid du Colombier 		error(Enomem);
407a9604be0SDavid du Colombier 	l = 0;
40846136019SDavid du Colombier 	l += snprint(p+l, READSTR-l, "tx: %uld\n", ctlr->stats.tx);
40946136019SDavid du Colombier 	l += snprint(p+l, READSTR-l, "tx [errs]: %uld\n", ctlr->stats.txe);
41046136019SDavid du Colombier 	l += snprint(p+l, READSTR-l, "rx: %uld\n", ctlr->stats.rx);
41146136019SDavid du Colombier 	l += snprint(p+l, READSTR-l, "intr: %uld\n", ctlr->stats.intr);
41246136019SDavid du Colombier 	snprint(p+l, READSTR-l, "\n");
413a9604be0SDavid du Colombier 
414a9604be0SDavid du Colombier 	n = readstr(offset, a, n, p);
415a9604be0SDavid du Colombier 	free(p);
416a9604be0SDavid du Colombier 
417a9604be0SDavid du Colombier 	return n;
418a9604be0SDavid du Colombier }
419a9604be0SDavid du Colombier 
420a9604be0SDavid du Colombier static char* vgbeisr_info[] = {
421a9604be0SDavid du Colombier 	"hi prio Rx int",
422a9604be0SDavid du Colombier 	"hi prio Tx int",
423a9604be0SDavid du Colombier 	"Rx queue completed",
424a9604be0SDavid du Colombier 	"One of Tx queues completed",
425a9604be0SDavid du Colombier 	"Tx queue 0 completed",
426a9604be0SDavid du Colombier 	"Tx queue 1 completed",
427a9604be0SDavid du Colombier 	"Tx queue 2 completed",
428a9604be0SDavid du Colombier 	"Tx queue 3 completed",
429a9604be0SDavid du Colombier 	"reserved",
430a9604be0SDavid du Colombier 	"reserved",
431a9604be0SDavid du Colombier 	"Rx packet count overflow",
432a9604be0SDavid du Colombier 	"pause frame Rx'ed",
433a9604be0SDavid du Colombier 	"RX FIFO overflow",
434a9604be0SDavid du Colombier 	"ran out of Rx descriptors",
435a9604be0SDavid du Colombier 	"running out of Rx descriptors",
436a9604be0SDavid du Colombier 	"link status change",
437a9604be0SDavid du Colombier 	"one shot timer expired",
438a9604be0SDavid du Colombier 	"periodic timer expired",
439a9604be0SDavid du Colombier 	"wake up power event",
440a9604be0SDavid du Colombier 	"PHY interrupt",
441a9604be0SDavid du Colombier 	"software shutdown complete",
442a9604be0SDavid du Colombier 	"MIB counter overflow warning",
443a9604be0SDavid du Colombier 	"software interrupt",
444a9604be0SDavid du Colombier 	"reload hold timer",
445a9604be0SDavid du Colombier 	"Rx DMA stall",
446a9604be0SDavid du Colombier 	"Tx DMA stall",
447a9604be0SDavid du Colombier 	"reserved",
448a9604be0SDavid du Colombier 	"reserved",
449a9604be0SDavid du Colombier 	"interrupt source indication 0",
450a9604be0SDavid du Colombier 	"interrupt source indication 1",
451a9604be0SDavid du Colombier 	"interrupt source indication 2",
452a9604be0SDavid du Colombier 	"interrupt source indication 3",
453a9604be0SDavid du Colombier };
454a9604be0SDavid du Colombier 
455a9604be0SDavid du Colombier static void
vgbedumpisr(ulong isr)456a9604be0SDavid du Colombier vgbedumpisr(ulong isr)
457a9604be0SDavid du Colombier {
458a9604be0SDavid du Colombier 	int i;
459a9604be0SDavid du Colombier 
460a9604be0SDavid du Colombier 	for(i = 0; i < 32; i++){
461a9604be0SDavid du Colombier 		ulong mask;
462a9604be0SDavid du Colombier 
463a9604be0SDavid du Colombier 		mask = 1<<i;
464a9604be0SDavid du Colombier 		if(isr & mask)
465a9604be0SDavid du Colombier 			print("vgbe: irq:  - %02d : %c %s\n", i,
466a9604be0SDavid du Colombier 			 	Isr_Mask & mask ? '*' : '-', vgbeisr_info[i]);
467a9604be0SDavid du Colombier 	}
468a9604be0SDavid du Colombier }
469a9604be0SDavid du Colombier 
470300dfd2bSDavid du Colombier static void
noop(Block *)471300dfd2bSDavid du Colombier noop(Block *)
472300dfd2bSDavid du Colombier {
473300dfd2bSDavid du Colombier }
474300dfd2bSDavid du Colombier 
475a9604be0SDavid du Colombier static int
vgbenewrx(Ctlr * ctlr,int i)476a9604be0SDavid du Colombier vgbenewrx(Ctlr* ctlr, int i)
477a9604be0SDavid du Colombier {
478a9604be0SDavid du Colombier 	Block* block;
479a9604be0SDavid du Colombier 	RxDesc* desc;
480a9604be0SDavid du Colombier 
481300dfd2bSDavid du Colombier 	/*
482300dfd2bSDavid du Colombier 	 * allocate a receive Block.  we're maintaining
483300dfd2bSDavid du Colombier 	 * a private pool of Blocks, so we don't want freeb
484300dfd2bSDavid du Colombier 	 * to actually free them, thus we set block->free.
485300dfd2bSDavid du Colombier 	 */
486a9604be0SDavid du Colombier 	block = allocb(RxSize);
487300dfd2bSDavid du Colombier 	block->free = noop;
488a9604be0SDavid du Colombier 
489a9604be0SDavid du Colombier 	/* Remember that block. */
490a9604be0SDavid du Colombier 	ctlr->rx_blocks[i] = block;
491a9604be0SDavid du Colombier 
492a9604be0SDavid du Colombier 	/* Initialize Rx descriptor. (TODO: 48/64 bits support ?) */
493a9604be0SDavid du Colombier 	desc = &ctlr->rx_ring[i];
494a9604be0SDavid du Colombier 	desc->status = htole32(RxDesc_Status_Own);
495a9604be0SDavid du Colombier 	desc->control = htole32(0);
496a9604be0SDavid du Colombier 
497a9604be0SDavid du Colombier 	desc->addr_lo = htole32((ulong)PCIWADDR(block->rp));
498a9604be0SDavid du Colombier 	desc->addr_hi = htole16(0);
499a9604be0SDavid du Colombier 	desc->length = htole16(RxSize | 0x8000);
500a9604be0SDavid du Colombier 
501a9604be0SDavid du Colombier 	return 0;
502a9604be0SDavid du Colombier }
503a9604be0SDavid du Colombier 
504a9604be0SDavid du Colombier static void
vgberxeof(Ether * edev)505a9604be0SDavid du Colombier vgberxeof(Ether* edev)
506a9604be0SDavid du Colombier {
507a9604be0SDavid du Colombier 	Ctlr* ctlr;
508a9604be0SDavid du Colombier 	int i;
509a9604be0SDavid du Colombier 	Block* block;
510a9604be0SDavid du Colombier 	ulong length, status;
511a9604be0SDavid du Colombier 	RxDesc* desc;
512a9604be0SDavid du Colombier 
513a9604be0SDavid du Colombier 	ctlr = edev->ctlr;
514a9604be0SDavid du Colombier 
515a9604be0SDavid du Colombier 	if(ctlr->debugflags & DumpRx)
516a9604be0SDavid du Colombier 		print("vgbe: rx_eof\n");
517a9604be0SDavid du Colombier 
518a9604be0SDavid du Colombier 	for(i = 0; i < RxCount; i++){
519a9604be0SDavid du Colombier 		/* Remember that block. */
520a9604be0SDavid du Colombier 		desc = &ctlr->rx_ring[i];
521a9604be0SDavid du Colombier 
522a9604be0SDavid du Colombier 		status = le32toh(desc->status);
523a9604be0SDavid du Colombier 
524a9604be0SDavid du Colombier 		if(status & RxDesc_Status_Own)
525a9604be0SDavid du Colombier 			continue;
526a9604be0SDavid du Colombier 
527a9604be0SDavid du Colombier 		if(status & RxDesc_Status_Goodframe){
528a9604be0SDavid du Colombier 			length = status >> RxDesc_Status_SizShift;
529a9604be0SDavid du Colombier 			length &= RxDesc_Status_SizMask;
530a9604be0SDavid du Colombier 
531a9604be0SDavid du Colombier 			if(ctlr->debugflags & DumpRx)
532a9604be0SDavid du Colombier 				print("vgbe: Rx-desc[%03d] status=%#08ulx ctl=%#08ulx len=%uld bytes\n",
533a9604be0SDavid du Colombier 					i, status, desc->control, length);
534a9604be0SDavid du Colombier 
535a9604be0SDavid du Colombier 			block = ctlr->rx_blocks[i];
536a9604be0SDavid du Colombier 			block->wp = block->rp + length;
537a9604be0SDavid du Colombier 
538a9604be0SDavid du Colombier 			ctlr->stats.rx++;
539300dfd2bSDavid du Colombier 			etheriq(edev, block, 1);
540a9604be0SDavid du Colombier 		}
541a9604be0SDavid du Colombier 		else
542a9604be0SDavid du Colombier 			print("vgbe: Rx-desc[%#02x] *BAD FRAME* status=%#08ulx ctl=%#08ulx\n",
543a9604be0SDavid du Colombier 				i, status, desc->control);
544a9604be0SDavid du Colombier 
545a9604be0SDavid du Colombier 		/* reset packet ... */
546a9604be0SDavid du Colombier 		desc->status = htole32(RxDesc_Status_Own);
547a9604be0SDavid du Colombier 		desc->control = htole32(0);
548a9604be0SDavid du Colombier 	}
549a9604be0SDavid du Colombier 
550a9604be0SDavid du Colombier 	if(ctlr->debugflags & DumpRx)
551a9604be0SDavid du Colombier 		print("vgbe: rx_eof: done\n");
552a9604be0SDavid du Colombier 
553a9604be0SDavid du Colombier 	wiow(ctlr, RxResCnt, RxCount);
554a9604be0SDavid du Colombier 	wiob(ctlr, RxCsrS, RxCsr_Wakeup);
555a9604be0SDavid du Colombier }
556a9604be0SDavid du Colombier 
557a9604be0SDavid du Colombier static void
vgbetxeof(Ether * edev)558a9604be0SDavid du Colombier vgbetxeof(Ether* edev)
559a9604be0SDavid du Colombier {
560a9604be0SDavid du Colombier 	Ctlr* ctlr;
561a9604be0SDavid du Colombier 	int i, count;
562a9604be0SDavid du Colombier 	Block* block;
563a9604be0SDavid du Colombier 	ulong status;
564a9604be0SDavid du Colombier 
565a9604be0SDavid du Colombier 	ctlr = edev->ctlr;
566a9604be0SDavid du Colombier 
567a9604be0SDavid du Colombier 	ilock(&ctlr->tx_lock);
568a9604be0SDavid du Colombier 
569a9604be0SDavid du Colombier 	if(ctlr->debugflags & DumpTx)
570a9604be0SDavid du Colombier 		print("vgbe: tx_eof\n");
571a9604be0SDavid du Colombier 
572a9604be0SDavid du Colombier 	for(count = 0, i = 0; i < TxCount; i++){
573a9604be0SDavid du Colombier 		block = ctlr->tx_blocks[i];
574a9604be0SDavid du Colombier 		if(block == nil)
575a9604be0SDavid du Colombier 			continue;
576a9604be0SDavid du Colombier 
577a9604be0SDavid du Colombier 		status = le32toh(ctlr->tx_ring[i].status);
578a9604be0SDavid du Colombier 		if(status & TxDesc_Status_Own)
579a9604be0SDavid du Colombier 			continue;
580a9604be0SDavid du Colombier 
581a9604be0SDavid du Colombier 		/* Todo add info if it failed */
582a9604be0SDavid du Colombier 		ctlr->stats.tx++;
583a9604be0SDavid du Colombier 
584a9604be0SDavid du Colombier 		if(ctlr->debugflags & DumpTx)
585a9604be0SDavid du Colombier 			print("vgbe: Block[%03d]:%#p has been sent\n", i, block);
586a9604be0SDavid du Colombier 
587a9604be0SDavid du Colombier 		count++;
588a9604be0SDavid du Colombier 		ctlr->tx_blocks[i] = nil;
589a9604be0SDavid du Colombier 		freeb(block);
590a9604be0SDavid du Colombier 
591a9604be0SDavid du Colombier 		if(ctlr->debugflags & DumpTx)
592a9604be0SDavid du Colombier 			print("vgbe: Block[%03d]:%#p has been freed\n", i, block);
593a9604be0SDavid du Colombier 	}
594a9604be0SDavid du Colombier 	ctlr->tx_count -= count;
595a9604be0SDavid du Colombier 
596a9604be0SDavid du Colombier 	if(ctlr->debugflags & DumpTx)
597a9604be0SDavid du Colombier 		print("vgbe: tx_eof: done [count=%d]\n", count);
598a9604be0SDavid du Colombier 
599a9604be0SDavid du Colombier 	iunlock(&ctlr->tx_lock);
600a9604be0SDavid du Colombier 
601a9604be0SDavid du Colombier 	if(ctlr->tx_count)
602a9604be0SDavid du Colombier 		wiob(ctlr, TxCsrS, TxCsr_Wakeup);
603a9604be0SDavid du Colombier }
604a9604be0SDavid du Colombier 
605a9604be0SDavid du Colombier static void
vgbeinterrupt(Ureg *,void * arg)606a9604be0SDavid du Colombier vgbeinterrupt(Ureg *, void* arg)
607a9604be0SDavid du Colombier {
608a9604be0SDavid du Colombier 	Ether* edev;
609a9604be0SDavid du Colombier 	Ctlr* ctlr;
610a9604be0SDavid du Colombier 	ulong status;
611a9604be0SDavid du Colombier 
612a9604be0SDavid du Colombier 	edev = (Ether *) arg;
613a9604be0SDavid du Colombier 	if(edev == nil)
614a9604be0SDavid du Colombier 		return;
615a9604be0SDavid du Colombier 
616a9604be0SDavid du Colombier 	ctlr = edev->ctlr;
617a9604be0SDavid du Colombier 	if(ctlr == nil)
618a9604be0SDavid du Colombier 		return;
619a9604be0SDavid du Colombier 
620a9604be0SDavid du Colombier 	/* Mask interrupts. */
621a9604be0SDavid du Colombier 	wiol(ctlr, Imr, 0);
622a9604be0SDavid du Colombier 
623a9604be0SDavid du Colombier 	status = riol(ctlr, Isr);
624a9604be0SDavid du Colombier 	if(status == 0xffff)
625a9604be0SDavid du Colombier 		goto end;
626a9604be0SDavid du Colombier 
627a9604be0SDavid du Colombier 	/* acknowledge */
628a9604be0SDavid du Colombier 	if(status)
629a9604be0SDavid du Colombier 		wiol(ctlr, Isr, status);
630a9604be0SDavid du Colombier 
631a9604be0SDavid du Colombier 	if((status & Isr_Mask) == 0)
632a9604be0SDavid du Colombier 		goto end;
633a9604be0SDavid du Colombier 
634a9604be0SDavid du Colombier 	ctlr->stats.intr++;
635a9604be0SDavid du Colombier 
636a9604be0SDavid du Colombier 	if(ctlr->debugflags & DumpIntr)
637a9604be0SDavid du Colombier 		if(ctlr->debugcount){
638a9604be0SDavid du Colombier 			print("vgbe: irq: status = %#08ulx\n", status);
639a9604be0SDavid du Colombier 			vgbedumpisr(status);
640a9604be0SDavid du Colombier 			ctlr->debugcount--;
641a9604be0SDavid du Colombier 		}
642a9604be0SDavid du Colombier 
643a9604be0SDavid du Colombier 	if(status & Isr_RxComplete)
644a9604be0SDavid du Colombier 		vgberxeof(edev);
645a9604be0SDavid du Colombier 
646a9604be0SDavid du Colombier 	if(status & Isr_TxComplete0)
647a9604be0SDavid du Colombier 		vgbetxeof(edev);
648a9604be0SDavid du Colombier 
649a9604be0SDavid du Colombier 	if(status & Isr_Stopped)
650a9604be0SDavid du Colombier 		print("vgbe: irq: software shutdown complete\n");
651a9604be0SDavid du Colombier 
652a9604be0SDavid du Colombier 	if(status & Isr_RxFifoOvflow)
653a9604be0SDavid du Colombier 		print("vgbe: irq: RX FIFO overflow\n");
654a9604be0SDavid du Colombier 
655a9604be0SDavid du Colombier 	if(status & Isr_PhyIntr)
656a9604be0SDavid du Colombier 		print("vgbe: irq: PHY interrupt\n");
657a9604be0SDavid du Colombier 
658a9604be0SDavid du Colombier 	if(status & Isr_LinkStatus)
659a9604be0SDavid du Colombier 		print("vgbe: irq: link status change\n");
660a9604be0SDavid du Colombier 
661a9604be0SDavid du Colombier 	if(status & Isr_RxNoDesc)
662a9604be0SDavid du Colombier 		print("vgbe: irq: ran out of Rx descriptors\n");
663a9604be0SDavid du Colombier 
664a9604be0SDavid du Colombier 	if(status & Isr_RxDmaStall){
665a9604be0SDavid du Colombier 		print("vgbe: irq: Rx DMA stall\n");
666a9604be0SDavid du Colombier 		wiol(ctlr, Cr3C, Cr3_IntMask);
667a9604be0SDavid du Colombier 		return;
668a9604be0SDavid du Colombier 	}
669a9604be0SDavid du Colombier 
670a9604be0SDavid du Colombier 	if(status & Isr_TxDmaStall){
671a9604be0SDavid du Colombier 		print("vgbe: irq: Tx DMA stall\n");
672a9604be0SDavid du Colombier 		wiol(ctlr, Cr3C, Cr3_IntMask);
673a9604be0SDavid du Colombier 		return;
674a9604be0SDavid du Colombier 	}
675a9604be0SDavid du Colombier 
676a9604be0SDavid du Colombier end:
677a9604be0SDavid du Colombier 	/* Unmask interrupts. */
678a9604be0SDavid du Colombier 	wiol(ctlr, Imr, ~0);
679a9604be0SDavid du Colombier }
680a9604be0SDavid du Colombier 
681a9604be0SDavid du Colombier static void
vgbetransmit(Ether * edev)682a9604be0SDavid du Colombier vgbetransmit(Ether* edev)
683a9604be0SDavid du Colombier {
684a9604be0SDavid du Colombier 	Block* block;
685a9604be0SDavid du Colombier 	Ctlr* ctlr;
686a9604be0SDavid du Colombier 	int i, index, start, count;
687a9604be0SDavid du Colombier 	TxDesc* desc;
688a9604be0SDavid du Colombier 	ulong status, length;
689a9604be0SDavid du Colombier 
690a9604be0SDavid du Colombier 	ctlr = edev->ctlr;
691a9604be0SDavid du Colombier 
692a9604be0SDavid du Colombier 	ilock(&ctlr->tx_lock);
693a9604be0SDavid du Colombier 
694a9604be0SDavid du Colombier 	start = riow(ctlr, TxDscIdx);
695a9604be0SDavid du Colombier 
696a9604be0SDavid du Colombier 	if(ctlr->debugflags & DumpTx)
697a9604be0SDavid du Colombier 		print("vgbe: transmit (start=%d)\n", start);
698a9604be0SDavid du Colombier 
699a9604be0SDavid du Colombier 	/* find empty slot */
700a9604be0SDavid du Colombier 	for(count = 0, i = 0; i < TxCount; i++){
701a9604be0SDavid du Colombier 		index = (i + start) % TxCount;
702a9604be0SDavid du Colombier 
703a9604be0SDavid du Colombier 		if(ctlr->tx_blocks[index])
704a9604be0SDavid du Colombier 			continue;
705a9604be0SDavid du Colombier 
706a9604be0SDavid du Colombier 		desc = &ctlr->tx_ring[index];
707a9604be0SDavid du Colombier 
708a9604be0SDavid du Colombier 		status = le32toh(desc->status);
709a9604be0SDavid du Colombier 		if(status & TxDesc_Status_Own)
710a9604be0SDavid du Colombier 			continue;
711a9604be0SDavid du Colombier 
712a9604be0SDavid du Colombier 		block = qget(edev->oq);
713a9604be0SDavid du Colombier 		if(block == nil)
714a9604be0SDavid du Colombier 			break;
715a9604be0SDavid du Colombier 
716a9604be0SDavid du Colombier 		count++;
717a9604be0SDavid du Colombier 
718a9604be0SDavid du Colombier 		length = BLEN(block);
719a9604be0SDavid du Colombier 
720a9604be0SDavid du Colombier 		if(ctlr->debugflags & DumpTx)
721a9604be0SDavid du Colombier 			print("vgbe: Tx-Desc[%03d] Block:%#p, addr=%#08ulx, len:%ld\n", index, block,
722a9604be0SDavid du Colombier 				PCIWADDR(block->rp), length);
723a9604be0SDavid du Colombier 
724a9604be0SDavid du Colombier 		ctlr->tx_blocks[index] = block;
725a9604be0SDavid du Colombier 
726a9604be0SDavid du Colombier 		/* Initialize Tx descriptor. */
727a9604be0SDavid du Colombier 		desc->status = htole32((length<<16)|TxDesc_Status_Own);
728a9604be0SDavid du Colombier 		desc->control = htole32(TxDesc_Control_Intr|TxDesc_Control_Normal|((1+1)<<28));
729a9604be0SDavid du Colombier 
730a9604be0SDavid du Colombier 		desc->frags[0].addr_lo = htole32((ulong) PCIWADDR(block->rp));
731a9604be0SDavid du Colombier 		desc->frags[0].addr_hi = htole16(0);
732a9604be0SDavid du Colombier 		desc->frags[0].length = htole16(length);
733a9604be0SDavid du Colombier 	}
734a9604be0SDavid du Colombier 	ctlr->tx_count += count;
735a9604be0SDavid du Colombier 
736a9604be0SDavid du Colombier 	if(ctlr->debugflags & DumpTx)
737a9604be0SDavid du Colombier 		print("vgbe: transmit: done [count=%d]\n", count);
738a9604be0SDavid du Colombier 
739a9604be0SDavid du Colombier 	iunlock(&ctlr->tx_lock);
740a9604be0SDavid du Colombier 
741a9604be0SDavid du Colombier 	if(ctlr->tx_count)
742a9604be0SDavid du Colombier 		wiob(ctlr, TxCsrS, TxCsr_Wakeup);
743a9604be0SDavid du Colombier 
744*6083aa43SDavid du Colombier 	if((ctlr->debugflags & DumpTx) && count == 0)
745a9604be0SDavid du Colombier 		print("vgbe: transmit: no Tx entry available\n");
746a9604be0SDavid du Colombier }
747a9604be0SDavid du Colombier 
748a9604be0SDavid du Colombier static void
vgbeattach(Ether * edev)749a9604be0SDavid du Colombier vgbeattach(Ether* edev)
750a9604be0SDavid du Colombier {
751a9604be0SDavid du Colombier 	Ctlr* ctlr;
752a9604be0SDavid du Colombier 	RxDesc* rxdesc;
753a9604be0SDavid du Colombier 	TxDesc* txdesc;
754a9604be0SDavid du Colombier 	int i;
755a9604be0SDavid du Colombier 
756a9604be0SDavid du Colombier 	ctlr = edev->ctlr;
757a9604be0SDavid du Colombier 
758a9604be0SDavid du Colombier 	lock(&ctlr->init_lock);
759a9604be0SDavid du Colombier 	if(ctlr->inited){
760a9604be0SDavid du Colombier 		unlock(&ctlr->init_lock);
761a9604be0SDavid du Colombier 		return;
762a9604be0SDavid du Colombier 	}
763a9604be0SDavid du Colombier 
764a9604be0SDavid du Colombier //	print("vgbe: attach\n");
765a9604be0SDavid du Colombier 
766a9604be0SDavid du Colombier 	/* Allocate Rx ring.  (TODO: Alignment ?) */
767a9604be0SDavid du Colombier 	rxdesc = mallocalign(RxCount* sizeof(RxDesc), 256, 0, 0);
768a9604be0SDavid du Colombier 	if(rxdesc == nil){
769a9604be0SDavid du Colombier 		print("vgbe: unable to alloc Rx ring\n");
770a9604be0SDavid du Colombier 		unlock(&ctlr->init_lock);
771a9604be0SDavid du Colombier 		return;
772a9604be0SDavid du Colombier 	}
773a9604be0SDavid du Colombier 	ctlr->rx_ring = rxdesc;
774a9604be0SDavid du Colombier 
775a9604be0SDavid du Colombier 	/* Allocate Rx blocks, initialize Rx ring. */
776a9604be0SDavid du Colombier 	for(i = 0; i < RxCount; i++)
777a9604be0SDavid du Colombier 		vgbenewrx(ctlr, i);
778a9604be0SDavid du Colombier 
779a9604be0SDavid du Colombier 	/* Init Rx MAC. */
780a9604be0SDavid du Colombier 	wiob(ctlr, RxControl,
781a9604be0SDavid du Colombier 		RxControl_MultiCast|RxControl_BroadCast|RxControl_UniCast);
782a9604be0SDavid du Colombier 	wiob(ctlr, RxConfig, RxConfig_VlanOpt0);
783a9604be0SDavid du Colombier 
784a9604be0SDavid du Colombier 	/* Load Rx ring. */
785a9604be0SDavid du Colombier 	wiol(ctlr, RxDescLo, (ulong) PCIWADDR(rxdesc));
786a9604be0SDavid du Colombier 	wiow(ctlr, RxNum, RxCount - 1);
787a9604be0SDavid du Colombier 	wiow(ctlr, RxDscIdx, 0);
788a9604be0SDavid du Colombier 	wiow(ctlr, RxResCnt, RxCount);
789a9604be0SDavid du Colombier 
790a9604be0SDavid du Colombier 	/* Allocate Tx ring. */
791a9604be0SDavid du Colombier 	txdesc = mallocalign(TxCount* sizeof(TxDesc), 256, 0, 0);
792a9604be0SDavid du Colombier 	if(txdesc == nil){
793a9604be0SDavid du Colombier 		print("vgbe: unable to alloc Tx ring\n");
794a9604be0SDavid du Colombier 		unlock(&ctlr->init_lock);
795a9604be0SDavid du Colombier 		return;
796a9604be0SDavid du Colombier 	}
797a9604be0SDavid du Colombier 	ctlr->tx_ring = txdesc;
798a9604be0SDavid du Colombier 
799a9604be0SDavid du Colombier 	/* Init DMAs */
800a9604be0SDavid du Colombier 	wiob(ctlr, DmaCfg0, 4);
801a9604be0SDavid du Colombier 
802a9604be0SDavid du Colombier 	/* Init Tx MAC. */
803a9604be0SDavid du Colombier 	wiob(ctlr, TxControl, 0);
804a9604be0SDavid du Colombier 	wiob(ctlr, TxConfig, TxConfig_NonBlk|TxConfig_ArbPrio);
805a9604be0SDavid du Colombier 
806a9604be0SDavid du Colombier 	/* Load Tx ring. */
807a9604be0SDavid du Colombier 	wiol(ctlr, TxDescLo, (ulong) PCIWADDR(txdesc));
808a9604be0SDavid du Colombier 	wiow(ctlr, TxNum, TxCount - 1);
809a9604be0SDavid du Colombier 	wiow(ctlr, TxDscIdx, 0);
810a9604be0SDavid du Colombier 
811a9604be0SDavid du Colombier 	/* Enable Xon/Xoff */
812a9604be0SDavid du Colombier 	wiob(ctlr, Cr2S, 0xb|Cr2_XonEnable);
813a9604be0SDavid du Colombier 
814a9604be0SDavid du Colombier 	/* Enable Rx queue */
815a9604be0SDavid du Colombier 	wiob(ctlr, RxCsrS, RxCsr_RunQueue);
816a9604be0SDavid du Colombier 
817a9604be0SDavid du Colombier 	/* Enable Tx queue */
818a9604be0SDavid du Colombier 	wiob(ctlr, TxCsrS, TxCsr_RunQueue);
819a9604be0SDavid du Colombier 
820a9604be0SDavid du Colombier 	/* Done */
821a9604be0SDavid du Colombier 	ctlr->inited = 1;
822a9604be0SDavid du Colombier 	unlock(&ctlr->init_lock);
823a9604be0SDavid du Colombier 
824a9604be0SDavid du Colombier 	/* Enable interrupts */
825a9604be0SDavid du Colombier 	wiol(ctlr, Isr, 0xffffffff);
826a9604be0SDavid du Colombier 	wiob(ctlr, Cr3S, Cr3_IntMask);
827a9604be0SDavid du Colombier 
828a9604be0SDavid du Colombier 	/* Wake up Rx queue */
829a9604be0SDavid du Colombier 	wiob(ctlr, RxCsrS, RxCsr_Wakeup);
830a9604be0SDavid du Colombier }
831a9604be0SDavid du Colombier 
832a9604be0SDavid du Colombier static void
vgbereset(Ctlr * ctlr)833a9604be0SDavid du Colombier vgbereset(Ctlr* ctlr)
834a9604be0SDavid du Colombier {
835a9604be0SDavid du Colombier //	MiiPhy* phy;
836a9604be0SDavid du Colombier 	int timeo, i;
837a9604be0SDavid du Colombier 
838a9604be0SDavid du Colombier //	print("vgbe: reset\n");
839a9604be0SDavid du Colombier 
840a9604be0SDavid du Colombier 	/* Soft reset the controller. */
841a9604be0SDavid du Colombier 	wiob(ctlr, Cr1S, Cr1_reset);
842a9604be0SDavid du Colombier 
843a9604be0SDavid du Colombier 	for(timeo = 0; timeo < Timeout; timeo++)
844a9604be0SDavid du Colombier 		if((riob(ctlr, Cr1S) & Cr1_reset) == 0)
845a9604be0SDavid du Colombier 			break;
846a9604be0SDavid du Colombier 
847a9604be0SDavid du Colombier 	if(timeo >= Timeout){
848a9604be0SDavid du Colombier 		print("vgbe: softreset timeout\n");
849a9604be0SDavid du Colombier 		return;
850a9604be0SDavid du Colombier 	}
851a9604be0SDavid du Colombier 
852a9604be0SDavid du Colombier 	/* Reload eeprom. */
853a9604be0SDavid du Colombier 	siob(ctlr, Eecsr, Eecsr_Autold);
854a9604be0SDavid du Colombier 
855a9604be0SDavid du Colombier 	for(timeo = 0; timeo < Timeout; timeo++)
856a9604be0SDavid du Colombier 		if((riob(ctlr, Eecsr) & Eecsr_Autold) == 0)
857a9604be0SDavid du Colombier 			break;
858a9604be0SDavid du Colombier 
859a9604be0SDavid du Colombier 	if(timeo >= Timeout){
860a9604be0SDavid du Colombier 		print("vgbe: eeprom reload timeout\n");
861a9604be0SDavid du Colombier 		return;
862a9604be0SDavid du Colombier 	}
863a9604be0SDavid du Colombier 
864a9604be0SDavid du Colombier 	/* Load the MAC address. */
865a9604be0SDavid du Colombier 	for(i = 0; i < Eaddrlen; i++)
866a9604be0SDavid du Colombier 		ctlr->ea[i] = riob(ctlr, EthAddr+i);
867a9604be0SDavid du Colombier 
868a9604be0SDavid du Colombier 	/* Initialize interrupts. */
869a9604be0SDavid du Colombier 	wiol(ctlr, Isr, 0xffffffff);
870a9604be0SDavid du Colombier 	wiol(ctlr, Imr, 0xffffffff);
871a9604be0SDavid du Colombier 
872a9604be0SDavid du Colombier 	/* Disable interrupts. */
873a9604be0SDavid du Colombier 	wiol(ctlr, Cr3C, Cr3_IntMask);
874a9604be0SDavid du Colombier 
875a9604be0SDavid du Colombier 	/* 32 bits addresses only. (TODO: 64 bits ?) */
876a9604be0SDavid du Colombier 	wiol(ctlr, TxDescHi, 0);
877a9604be0SDavid du Colombier 	wiow(ctlr, DataBufHi, 0);
878a9604be0SDavid du Colombier 
879a9604be0SDavid du Colombier 	/* Enable MAC (turning off Rx/Tx engines for the moment). */
880a9604be0SDavid du Colombier 	wiob(ctlr, Cr0C, Cr0_Stop|Cr0_EnableRx|Cr0_EnableTx);
881a9604be0SDavid du Colombier 	wiob(ctlr, Cr0S, Cr0_Start);
882a9604be0SDavid du Colombier 
883a9604be0SDavid du Colombier 	/* Initialize Rx engine. */
884a9604be0SDavid du Colombier 	wiow(ctlr, RxCsrC, RxCsr_RunQueue);
885a9604be0SDavid du Colombier 
886a9604be0SDavid du Colombier 	/* Initialize Tx engine. */
887a9604be0SDavid du Colombier 	wiow(ctlr, TxCsrC, TxCsr_RunQueue);
888a9604be0SDavid du Colombier 
889a9604be0SDavid du Colombier 	/* Enable Rx/Tx engines. */
890a9604be0SDavid du Colombier 	wiob(ctlr, Cr0S, Cr0_EnableRx|Cr0_EnableTx);
891a9604be0SDavid du Colombier 
892a9604be0SDavid du Colombier 	/* Initialize link management. */
893a9604be0SDavid du Colombier 	ctlr->mii = malloc(sizeof(Mii));
894a9604be0SDavid du Colombier 	if(ctlr->mii == nil){
895a9604be0SDavid du Colombier 		print("vgbe: unable to alloc Mii\n");
896a9604be0SDavid du Colombier 		return;
897a9604be0SDavid du Colombier 	}
898a9604be0SDavid du Colombier 
899a9604be0SDavid du Colombier 	ctlr->mii->mir = vgbemiir;
900a9604be0SDavid du Colombier 	ctlr->mii->miw = vgbemiiw;
901a9604be0SDavid du Colombier 	ctlr->mii->ctlr = ctlr;
902a9604be0SDavid du Colombier 
903a9604be0SDavid du Colombier 	if(mii(ctlr->mii, 1<<1) == 0){
904a9604be0SDavid du Colombier 		print("vgbe: no phy found\n");
905a9604be0SDavid du Colombier 		return;
906a9604be0SDavid du Colombier 	}
907a9604be0SDavid du Colombier 
908a9604be0SDavid du Colombier //	phy = ctlr->mii->curphy;
909a9604be0SDavid du Colombier //	print("vgbe: phy:oui %#x\n", phy->oui);
910a9604be0SDavid du Colombier }
911a9604be0SDavid du Colombier 
912a9604be0SDavid du Colombier static void
vgbepci(void)913a9604be0SDavid du Colombier vgbepci(void)
914a9604be0SDavid du Colombier {
915a9604be0SDavid du Colombier 	Pcidev* pdev;
916a9604be0SDavid du Colombier 
917a9604be0SDavid du Colombier //	print("vgbe: pci\n");
918a9604be0SDavid du Colombier 
919a9604be0SDavid du Colombier 	pdev = nil;
920a9604be0SDavid du Colombier 	while(pdev = pcimatch(pdev, 0, 0)){
921a9604be0SDavid du Colombier 		Ctlr* ctlr;
922a9604be0SDavid du Colombier 		int port, size;
923a9604be0SDavid du Colombier 
924a9604be0SDavid du Colombier 		if(pdev->ccrb != 0x02 || pdev->ccru != 0)
925a9604be0SDavid du Colombier 			continue;
926a9604be0SDavid du Colombier 
927a9604be0SDavid du Colombier 		switch((pdev->did<<16) | pdev->vid){
928a9604be0SDavid du Colombier 		default:
929a9604be0SDavid du Colombier 			continue;
930a9604be0SDavid du Colombier 
931a9604be0SDavid du Colombier 		case (0x3119<<16)|0x1106:	/* VIA Velocity (VT6122) */
932a9604be0SDavid du Colombier 			break;
933a9604be0SDavid du Colombier 		}
934a9604be0SDavid du Colombier 
935a9604be0SDavid du Colombier 		if((pdev->pcr & 1) == 0){
936a9604be0SDavid du Colombier 			print("vgbe: io not enabled [pcr=%#lux]\n", (ulong)pdev->pcr);
937a9604be0SDavid du Colombier 			continue;
938a9604be0SDavid du Colombier 		}
939a9604be0SDavid du Colombier 
940a9604be0SDavid du Colombier 		pcisetbme(pdev);
941a9604be0SDavid du Colombier 		pcisetpms(pdev, 0);
942a9604be0SDavid du Colombier 
943a9604be0SDavid du Colombier 		port = pdev->mem[0].bar;
944a9604be0SDavid du Colombier 		size = pdev->mem[0].size;
945a9604be0SDavid du Colombier 
946a9604be0SDavid du Colombier 		if((port & 1) == 0){
947a9604be0SDavid du Colombier 			print("vgbe: bar[0]=%#x is not io\n", port);
948a9604be0SDavid du Colombier 			continue;
949a9604be0SDavid du Colombier 		}
950a9604be0SDavid du Colombier 
951a9604be0SDavid du Colombier 		if(port > 0xff00){
952a9604be0SDavid du Colombier 			print("vgbe: invalid port %#ux\n", port);
953a9604be0SDavid du Colombier 			continue;
954a9604be0SDavid du Colombier 		}
955a9604be0SDavid du Colombier 
956a9604be0SDavid du Colombier 		port &= 0xfffe;
957a9604be0SDavid du Colombier 
958a9604be0SDavid du Colombier 		if(size != 256){
959a9604be0SDavid du Colombier 			print("vgbe: invalid io size: %d\n", size);
960a9604be0SDavid du Colombier 			continue;
961a9604be0SDavid du Colombier 		}
962a9604be0SDavid du Colombier 
963a9604be0SDavid du Colombier 		if(ioalloc(port, size, 0, "vge") < 0){
964a9604be0SDavid du Colombier 			print("vgbe: port %#ux already in use\n", port);
965a9604be0SDavid du Colombier 			continue;
966a9604be0SDavid du Colombier 		}
967a9604be0SDavid du Colombier 
968a9604be0SDavid du Colombier 		ctlr = malloc(sizeof(Ctlr));
969a9604be0SDavid du Colombier 		if(ctlr == nil){
970a9604be0SDavid du Colombier 			print("vgbe: unable to alloc Ctlr\n");
971a9604be0SDavid du Colombier 			iofree(port);
972a9604be0SDavid du Colombier 			continue;
973a9604be0SDavid du Colombier 		}
974a9604be0SDavid du Colombier 
975a9604be0SDavid du Colombier 		ctlr->pdev = pdev;
976a9604be0SDavid du Colombier 		ctlr->port = port;
977a9604be0SDavid du Colombier 		ctlr->inited = 0;
978a9604be0SDavid du Colombier 
979a9604be0SDavid du Colombier 		if(vgbehead != nil)
980a9604be0SDavid du Colombier 			vgbetail->link = ctlr;
981a9604be0SDavid du Colombier 		else
982a9604be0SDavid du Colombier 			vgbehead = ctlr;
983a9604be0SDavid du Colombier 		vgbetail = ctlr;
984a9604be0SDavid du Colombier 	}
985a9604be0SDavid du Colombier }
986a9604be0SDavid du Colombier 
987a9604be0SDavid du Colombier static long
vgbectl(Ether * edev,void * buf,long n)988a9604be0SDavid du Colombier vgbectl(Ether* edev, void* buf, long n)
989a9604be0SDavid du Colombier {
990a9604be0SDavid du Colombier 	Cmdbuf* cb;
991a9604be0SDavid du Colombier 	Ctlr* ctlr;
992a9604be0SDavid du Colombier 	ulong index;
993a9604be0SDavid du Colombier 	char* rptr;
994a9604be0SDavid du Colombier 	RxDesc* rd;
995a9604be0SDavid du Colombier 	TxDesc* td;
996a9604be0SDavid du Colombier 	uchar* p;
997a9604be0SDavid du Colombier 
998a9604be0SDavid du Colombier 	ctlr = edev->ctlr;
999a9604be0SDavid du Colombier 
1000a9604be0SDavid du Colombier 	cb = parsecmd(buf, n);
1001a9604be0SDavid du Colombier 	if(waserror()){
1002a9604be0SDavid du Colombier 		free(cb);
1003a9604be0SDavid du Colombier 		nexterror();
1004a9604be0SDavid du Colombier 	}
1005a9604be0SDavid du Colombier 
1006a9604be0SDavid du Colombier 	if(cistrcmp(cb->f[0], "reset") == 0){
1007a9604be0SDavid du Colombier 		vgbereset(ctlr);
1008a9604be0SDavid du Colombier 		wiob(ctlr, Cr3S, Cr3_IntMask);
1009a9604be0SDavid du Colombier 		wiob(ctlr, RxCsrS, RxCsr_RunQueue);
1010a9604be0SDavid du Colombier 		wiob(ctlr, RxCsrS, RxCsr_Wakeup);
1011a9604be0SDavid du Colombier 	}
1012a9604be0SDavid du Colombier 	else if(cistrcmp(cb->f[0], "dumpintr") == 0){
1013a9604be0SDavid du Colombier 		if(cb->nf < 2)
1014a9604be0SDavid du Colombier 			error(Ecmdargs);
1015a9604be0SDavid du Colombier 
1016a9604be0SDavid du Colombier 		if(cistrcmp(cb->f[1], "on") == 0){
1017a9604be0SDavid du Colombier 			ctlr->debugflags |= DumpIntr;
1018a9604be0SDavid du Colombier 			ctlr->debugcount = ~0;
1019a9604be0SDavid du Colombier 		}
1020a9604be0SDavid du Colombier 		else if(cistrcmp(cb->f[1], "off") == 0)
1021a9604be0SDavid du Colombier 			ctlr->debugflags &= ~DumpIntr;
1022a9604be0SDavid du Colombier 		else{
1023a9604be0SDavid du Colombier 			ulong count;
1024a9604be0SDavid du Colombier 			char* rptr;
1025a9604be0SDavid du Colombier 
1026a9604be0SDavid du Colombier 			count = strtoul(cb->f[1], &rptr, 0);
1027a9604be0SDavid du Colombier 			if(rptr == cb->f[1])
1028a9604be0SDavid du Colombier 				error("invalid control request");
1029a9604be0SDavid du Colombier 
1030a9604be0SDavid du Colombier 			ctlr->debugflags |= DumpIntr;
1031a9604be0SDavid du Colombier 			ctlr->debugcount = count;
1032a9604be0SDavid du Colombier 
1033a9604be0SDavid du Colombier 			print("vgbe: debugcount set to %uld\n", count);
1034a9604be0SDavid du Colombier 		}
1035a9604be0SDavid du Colombier 	}
1036a9604be0SDavid du Colombier 	else if(cistrcmp(cb->f[0], "dumprx") == 0){
1037a9604be0SDavid du Colombier 		if(cb->nf < 2)
1038a9604be0SDavid du Colombier 			error(Ecmdargs);
1039a9604be0SDavid du Colombier 
1040a9604be0SDavid du Colombier 		if(cistrcmp(cb->f[1], "on") == 0)
1041a9604be0SDavid du Colombier 			ctlr->debugflags |= DumpRx;
1042a9604be0SDavid du Colombier 		else if(cistrcmp(cb->f[1], "off") == 0)
1043a9604be0SDavid du Colombier 			ctlr->debugflags &= ~DumpRx;
1044a9604be0SDavid du Colombier 		else{
1045a9604be0SDavid du Colombier 			index = strtoul(cb->f[1], &rptr, 0);
1046a9604be0SDavid du Colombier 			if((rptr == cb->f[1]) || (index >= RxCount))
1047a9604be0SDavid du Colombier 				error("invalid control request");
1048a9604be0SDavid du Colombier 
1049a9604be0SDavid du Colombier 			rd = &ctlr->rx_ring[index];
1050a9604be0SDavid du Colombier 			print("vgbe: DumpRx[%03uld] status=%#08ulx ctl=%#08ulx len=%#04ux bytes\n",
1051a9604be0SDavid du Colombier 				index, rd->status, rd->control, rd->length);
1052a9604be0SDavid du Colombier 		}
1053a9604be0SDavid du Colombier 	}
1054a9604be0SDavid du Colombier 	else if(cistrcmp(cb->f[0], "dumptx") == 0){
1055a9604be0SDavid du Colombier 		if(cb->nf < 2)
1056a9604be0SDavid du Colombier 			error(Ecmdargs);
1057a9604be0SDavid du Colombier 
1058a9604be0SDavid du Colombier 		if(cistrcmp(cb->f[1], "on") == 0)
1059a9604be0SDavid du Colombier 			ctlr->debugflags |= DumpTx;
1060a9604be0SDavid du Colombier 		else if(cistrcmp(cb->f[1], "off") == 0)
1061a9604be0SDavid du Colombier 			ctlr->debugflags &= ~DumpTx;
1062a9604be0SDavid du Colombier 		else{
1063a9604be0SDavid du Colombier 			index = strtoul(cb->f[1], &rptr, 0);
1064a9604be0SDavid du Colombier 			if((rptr == cb->f[1]) || (index >= TxCount))
1065a9604be0SDavid du Colombier 				error("invalid control request");
1066a9604be0SDavid du Colombier 
1067a9604be0SDavid du Colombier 			td = &ctlr->tx_ring[index];
1068a9604be0SDavid du Colombier 			print("vgbe: DumpTx[%03uld] status=%#08ulx ctl=%#08ulx len=%#04ux bytes",
1069a9604be0SDavid du Colombier 				index, td->status, td->control, td->frags[0].length);
1070a9604be0SDavid du Colombier 
1071a9604be0SDavid du Colombier 			p = (uchar*)td;
1072a9604be0SDavid du Colombier 			for(index = 0; index < sizeof(TxDesc); index++){
1073a9604be0SDavid du Colombier 				if((index % 16) == 0)
1074a9604be0SDavid du Colombier 					print("\nvgbe: ");
1075a9604be0SDavid du Colombier 				else
1076a9604be0SDavid du Colombier 					print(" ");
1077a9604be0SDavid du Colombier 				print("%#02x", p[index]);
1078a9604be0SDavid du Colombier 			}
1079a9604be0SDavid du Colombier 		}
1080a9604be0SDavid du Colombier 	}
1081a9604be0SDavid du Colombier 	else if(cistrcmp(cb->f[0], "dumpall") == 0){
1082a9604be0SDavid du Colombier 		if(cb->nf < 2)
1083a9604be0SDavid du Colombier 			error(Ecmdargs);
1084a9604be0SDavid du Colombier 
1085a9604be0SDavid du Colombier 		if(cistrcmp(cb->f[1], "on") == 0){
1086a9604be0SDavid du Colombier 			ctlr->debugflags = ~0;
1087a9604be0SDavid du Colombier 			ctlr->debugcount = ~0;
1088a9604be0SDavid du Colombier 		}
1089a9604be0SDavid du Colombier 		else if(cistrcmp(cb->f[1], "off") == 0)
1090a9604be0SDavid du Colombier 			ctlr->debugflags = 0;
1091a9604be0SDavid du Colombier 		else error("invalid control request");
1092a9604be0SDavid du Colombier 	}
1093a9604be0SDavid du Colombier 	else
1094a9604be0SDavid du Colombier 		error(Ebadctl);
1095a9604be0SDavid du Colombier 
1096a9604be0SDavid du Colombier 	free(cb);
1097a9604be0SDavid du Colombier 	poperror();
1098a9604be0SDavid du Colombier 
1099a9604be0SDavid du Colombier 	return n;
1100a9604be0SDavid du Colombier }
1101a9604be0SDavid du Colombier 
1102e183b1a6SDavid du Colombier static void
vgbepromiscuous(void * arg,int on)1103e183b1a6SDavid du Colombier vgbepromiscuous(void* arg, int on)
1104e183b1a6SDavid du Colombier {
1105e183b1a6SDavid du Colombier 	USED(arg, on);
1106e183b1a6SDavid du Colombier }
1107e183b1a6SDavid du Colombier 
1108e183b1a6SDavid du Colombier /* multicast already on, don't need to do anything */
1109e183b1a6SDavid du Colombier static void
vgbemulticast(void *,uchar *,int)1110e183b1a6SDavid du Colombier vgbemulticast(void*, uchar*, int)
1111e183b1a6SDavid du Colombier {
1112e183b1a6SDavid du Colombier }
1113e183b1a6SDavid du Colombier 
111498bee55eSDavid du Colombier static void
vgbeshutdown(Ether * ether)111598bee55eSDavid du Colombier vgbeshutdown(Ether* ether)
111698bee55eSDavid du Colombier {
111798bee55eSDavid du Colombier 	vgbereset(ether->ctlr);
111898bee55eSDavid du Colombier }
111998bee55eSDavid du Colombier 
1120a9604be0SDavid du Colombier static int
vgbepnp(Ether * edev)1121a9604be0SDavid du Colombier vgbepnp(Ether* edev)
1122a9604be0SDavid du Colombier {
1123a9604be0SDavid du Colombier 	Ctlr* ctlr;
1124a9604be0SDavid du Colombier 
1125a9604be0SDavid du Colombier //	print("vgbe: pnp\n");
1126a9604be0SDavid du Colombier 
1127a9604be0SDavid du Colombier 	if(vgbehead == nil)
1128a9604be0SDavid du Colombier 		vgbepci();
1129a9604be0SDavid du Colombier 
1130a9604be0SDavid du Colombier 	for(ctlr = vgbehead; ctlr != nil; ctlr = ctlr->link){
1131a9604be0SDavid du Colombier 		if(ctlr->active)
1132a9604be0SDavid du Colombier 			continue;
1133a9604be0SDavid du Colombier 
1134a9604be0SDavid du Colombier 		if(edev->port == 0 || edev->port == ctlr->port){
1135a9604be0SDavid du Colombier 			ctlr->active = 1;
1136a9604be0SDavid du Colombier 			break;
1137a9604be0SDavid du Colombier 		}
1138a9604be0SDavid du Colombier 	}
1139a9604be0SDavid du Colombier 
1140a9604be0SDavid du Colombier 	if(ctlr == nil)
1141a9604be0SDavid du Colombier 		return -1;
1142a9604be0SDavid du Colombier 
1143a9604be0SDavid du Colombier 	vgbereset(ctlr);
1144a9604be0SDavid du Colombier 
1145a9604be0SDavid du Colombier 	edev->ctlr = ctlr;
1146a9604be0SDavid du Colombier 	edev->port = ctlr->port;
1147a9604be0SDavid du Colombier 	edev->irq = ctlr->pdev->intl;
1148a9604be0SDavid du Colombier 	edev->tbdf = ctlr->pdev->tbdf;
1149a9604be0SDavid du Colombier 	edev->mbps = 1000;
1150a9604be0SDavid du Colombier 	memmove(edev->ea, ctlr->ea, Eaddrlen);
1151a9604be0SDavid du Colombier 	edev->attach = vgbeattach;
1152a9604be0SDavid du Colombier 	edev->transmit = vgbetransmit;
1153a9604be0SDavid du Colombier 	edev->interrupt = vgbeinterrupt;
1154a9604be0SDavid du Colombier 	edev->ifstat = vgbeifstat;
1155e183b1a6SDavid du Colombier //	edev->promiscuous = vgbepromiscuous;
1156e183b1a6SDavid du Colombier 	edev->multicast = vgbemulticast;
115798bee55eSDavid du Colombier 	edev->shutdown = vgbeshutdown;
1158a9604be0SDavid du Colombier 	edev->ctl = vgbectl;
1159a9604be0SDavid du Colombier 
1160a9604be0SDavid du Colombier 	edev->arg = edev;
1161a9604be0SDavid du Colombier 	return 0;
1162a9604be0SDavid du Colombier }
1163a9604be0SDavid du Colombier 
1164a9604be0SDavid du Colombier void
ethervgbelink(void)1165a9604be0SDavid du Colombier ethervgbelink(void)
1166a9604be0SDavid du Colombier {
1167a9604be0SDavid du Colombier 	addethercard("vgbe", vgbepnp);
1168a9604be0SDavid du Colombier }
1169