xref: /inferno-os/os/boot/pc/ether2114x.c (revision 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a)
1*74a4d8c2SCharles.Forsyth /*
2*74a4d8c2SCharles.Forsyth  * Digital Semiconductor DECchip 21140 PCI Fast Ethernet LAN Controller
3*74a4d8c2SCharles.Forsyth  * as found on the Digital Fast EtherWORKS PCI 10/100 adapter (DE-500-X).
4*74a4d8c2SCharles.Forsyth  * To do:
5*74a4d8c2SCharles.Forsyth  *	thresholds;
6*74a4d8c2SCharles.Forsyth  *	ring sizing;
7*74a4d8c2SCharles.Forsyth  *	handle more error conditions;
8*74a4d8c2SCharles.Forsyth  *	all the rest of it...
9*74a4d8c2SCharles.Forsyth  */
10*74a4d8c2SCharles.Forsyth #include "u.h"
11*74a4d8c2SCharles.Forsyth #include "lib.h"
12*74a4d8c2SCharles.Forsyth #include "mem.h"
13*74a4d8c2SCharles.Forsyth #include "dat.h"
14*74a4d8c2SCharles.Forsyth #include "fns.h"
15*74a4d8c2SCharles.Forsyth #include "io.h"
16*74a4d8c2SCharles.Forsyth 
17*74a4d8c2SCharles.Forsyth #include "etherif.h"
18*74a4d8c2SCharles.Forsyth 
19*74a4d8c2SCharles.Forsyth #define DEBUG		(0)
20*74a4d8c2SCharles.Forsyth #define debug		if(DEBUG)print
21*74a4d8c2SCharles.Forsyth 
22*74a4d8c2SCharles.Forsyth enum {
23*74a4d8c2SCharles.Forsyth 	Nrde		= 32,
24*74a4d8c2SCharles.Forsyth 	Ntde		= 4,
25*74a4d8c2SCharles.Forsyth };
26*74a4d8c2SCharles.Forsyth 
27*74a4d8c2SCharles.Forsyth #define Rbsz		ROUNDUP(sizeof(Etherpkt)+4, 4)
28*74a4d8c2SCharles.Forsyth 
29*74a4d8c2SCharles.Forsyth enum {					/* CRS0 - Bus Mode */
30*74a4d8c2SCharles.Forsyth 	Swr		= 0x00000001,	/* Software Reset */
31*74a4d8c2SCharles.Forsyth 	Bar		= 0x00000002,	/* Bus Arbitration */
32*74a4d8c2SCharles.Forsyth 	Dsl		= 0x0000007C,	/* Descriptor Skip Length (field) */
33*74a4d8c2SCharles.Forsyth 	Ble		= 0x00000080,	/* Big/Little Endian */
34*74a4d8c2SCharles.Forsyth 	Pbl		= 0x00003F00,	/* Programmable Burst Length (field) */
35*74a4d8c2SCharles.Forsyth 	Cal		= 0x0000C000,	/* Cache Alignment (field) */
36*74a4d8c2SCharles.Forsyth 	Cal8		= 0x00004000,	/* 8 longword boundary alignment */
37*74a4d8c2SCharles.Forsyth 	Cal16		= 0x00008000,	/* 16 longword boundary alignment */
38*74a4d8c2SCharles.Forsyth 	Cal32		= 0x0000C000,	/* 32 longword boundary alignment */
39*74a4d8c2SCharles.Forsyth 	Tap		= 0x000E0000,	/* Transmit Automatic Polling (field) */
40*74a4d8c2SCharles.Forsyth 	Dbo		= 0x00100000,	/* Descriptor Byte Ordering Mode */
41*74a4d8c2SCharles.Forsyth 	Rml		= 0x00200000,	/* Read Multiple */
42*74a4d8c2SCharles.Forsyth };
43*74a4d8c2SCharles.Forsyth 
44*74a4d8c2SCharles.Forsyth enum {					/* CSR[57] - Status and Interrupt Enable */
45*74a4d8c2SCharles.Forsyth 	Ti		= 0x00000001,	/* Transmit Interrupt */
46*74a4d8c2SCharles.Forsyth 	Tps		= 0x00000002,	/* Transmit Process Stopped */
47*74a4d8c2SCharles.Forsyth 	Tu		= 0x00000004,	/* Transmit buffer Unavailable */
48*74a4d8c2SCharles.Forsyth 	Tjt		= 0x00000008,	/* Transmit Jabber Timeout */
49*74a4d8c2SCharles.Forsyth 	Unf		= 0x00000020,	/* transmit UNderFlow */
50*74a4d8c2SCharles.Forsyth 	Ri		= 0x00000040,	/* Receive Interrupt */
51*74a4d8c2SCharles.Forsyth 	Ru		= 0x00000080,	/* Receive buffer Unavailable */
52*74a4d8c2SCharles.Forsyth 	Rps		= 0x00000100,	/* Receive Process Stopped */
53*74a4d8c2SCharles.Forsyth 	Rwt		= 0x00000200,	/* Receive Watchdog Timeout */
54*74a4d8c2SCharles.Forsyth 	Eti		= 0x00000400,	/* Early Transmit Interrupt */
55*74a4d8c2SCharles.Forsyth 	Gte		= 0x00000800,	/* General purpose Timer Expired */
56*74a4d8c2SCharles.Forsyth 	Fbe		= 0x00002000,	/* Fatal Bit Error */
57*74a4d8c2SCharles.Forsyth 	Ais		= 0x00008000,	/* Abnormal Interrupt Summary */
58*74a4d8c2SCharles.Forsyth 	Nis		= 0x00010000,	/* Normal Interrupt Summary */
59*74a4d8c2SCharles.Forsyth 	Rs		= 0x000E0000,	/* Receive process State (field) */
60*74a4d8c2SCharles.Forsyth 	Ts		= 0x00700000,	/* Transmit process State (field) */
61*74a4d8c2SCharles.Forsyth 	Eb		= 0x03800000,	/* Error bits */
62*74a4d8c2SCharles.Forsyth };
63*74a4d8c2SCharles.Forsyth 
64*74a4d8c2SCharles.Forsyth enum {					/* CSR6 - Operating Mode */
65*74a4d8c2SCharles.Forsyth 	Hp		= 0x00000001,	/* Hash/Perfect receive filtering mode */
66*74a4d8c2SCharles.Forsyth 	Sr		= 0x00000002,	/* Start/stop Receive */
67*74a4d8c2SCharles.Forsyth 	Ho		= 0x00000004,	/* Hash-Only filtering mode */
68*74a4d8c2SCharles.Forsyth 	Pb		= 0x00000008,	/* Pass Bad frames */
69*74a4d8c2SCharles.Forsyth 	If		= 0x00000010,	/* Inverse Filtering */
70*74a4d8c2SCharles.Forsyth 	Sb		= 0x00000020,	/* Start/stop Backoff counter */
71*74a4d8c2SCharles.Forsyth 	Pr		= 0x00000040,	/* Promiscuous Mode */
72*74a4d8c2SCharles.Forsyth 	Pm		= 0x00000080,	/* Pass all Multicast */
73*74a4d8c2SCharles.Forsyth 	Fd		= 0x00000200,	/* Full Duplex mode */
74*74a4d8c2SCharles.Forsyth 	Om		= 0x00000C00,	/* Operating Mode (field) */
75*74a4d8c2SCharles.Forsyth 	Fc		= 0x00001000,	/* Force Collision */
76*74a4d8c2SCharles.Forsyth 	St		= 0x00002000,	/* Start/stop Transmission Command */
77*74a4d8c2SCharles.Forsyth 	Tr		= 0x0000C000,	/* ThReshold control bits (field) */
78*74a4d8c2SCharles.Forsyth 	Tr128		= 0x00000000,
79*74a4d8c2SCharles.Forsyth 	Tr256		= 0x00004000,
80*74a4d8c2SCharles.Forsyth 	Tr512		= 0x00008000,
81*74a4d8c2SCharles.Forsyth 	Tr1024		= 0x0000C000,
82*74a4d8c2SCharles.Forsyth 	Ca		= 0x00020000,	/* CApture effect enable */
83*74a4d8c2SCharles.Forsyth 	Ps		= 0x00040000,	/* Port Select */
84*74a4d8c2SCharles.Forsyth 	Hbd		= 0x00080000,	/* HeartBeat Disable */
85*74a4d8c2SCharles.Forsyth 	Imm		= 0x00100000,	/* IMMediate mode */
86*74a4d8c2SCharles.Forsyth 	Sf		= 0x00200000,	/* Store and Forward */
87*74a4d8c2SCharles.Forsyth 	Ttm		= 0x00400000,	/* Transmit Threshold Mode */
88*74a4d8c2SCharles.Forsyth 	Pcs		= 0x00800000,	/* PCS function */
89*74a4d8c2SCharles.Forsyth 	Scr		= 0x01000000,	/* SCRambler mode */
90*74a4d8c2SCharles.Forsyth 	Mbo		= 0x02000000,	/* Must Be One */
91*74a4d8c2SCharles.Forsyth 	Ra		= 0x40000000,	/* Receive All */
92*74a4d8c2SCharles.Forsyth 	Sc		= 0x80000000,	/* Special Capture effect enable */
93*74a4d8c2SCharles.Forsyth 
94*74a4d8c2SCharles.Forsyth 	TrMODE		= Tr512,	/* default transmission threshold */
95*74a4d8c2SCharles.Forsyth };
96*74a4d8c2SCharles.Forsyth 
97*74a4d8c2SCharles.Forsyth enum {					/* CSR9 - ROM and MII Management */
98*74a4d8c2SCharles.Forsyth 	Scs		= 0x00000001,	/* serial ROM chip select */
99*74a4d8c2SCharles.Forsyth 	Sclk		= 0x00000002,	/* serial ROM clock */
100*74a4d8c2SCharles.Forsyth 	Sdi		= 0x00000004,	/* serial ROM data in */
101*74a4d8c2SCharles.Forsyth 	Sdo		= 0x00000008,	/* serial ROM data out */
102*74a4d8c2SCharles.Forsyth 	Ss		= 0x00000800,	/* serial ROM select */
103*74a4d8c2SCharles.Forsyth 	Wr		= 0x00002000,	/* write */
104*74a4d8c2SCharles.Forsyth 	Rd		= 0x00004000,	/* read */
105*74a4d8c2SCharles.Forsyth 
106*74a4d8c2SCharles.Forsyth 	Mdc		= 0x00010000,	/* MII management clock */
107*74a4d8c2SCharles.Forsyth 	Mdo		= 0x00020000,	/* MII management write data */
108*74a4d8c2SCharles.Forsyth 	Mii		= 0x00040000,	/* MII management operation mode (W) */
109*74a4d8c2SCharles.Forsyth 	Mdi		= 0x00080000,	/* MII management data in */
110*74a4d8c2SCharles.Forsyth };
111*74a4d8c2SCharles.Forsyth 
112*74a4d8c2SCharles.Forsyth enum {					/* CSR12 - General-Purpose Port */
113*74a4d8c2SCharles.Forsyth 	Gpc		= 0x00000100,	/* General Purpose Control */
114*74a4d8c2SCharles.Forsyth };
115*74a4d8c2SCharles.Forsyth 
116*74a4d8c2SCharles.Forsyth typedef struct Des {
117*74a4d8c2SCharles.Forsyth 	int	status;
118*74a4d8c2SCharles.Forsyth 	int	control;
119*74a4d8c2SCharles.Forsyth 	ulong	addr;
120*74a4d8c2SCharles.Forsyth 	void*	bp;
121*74a4d8c2SCharles.Forsyth } Des;
122*74a4d8c2SCharles.Forsyth 
123*74a4d8c2SCharles.Forsyth enum {					/* status */
124*74a4d8c2SCharles.Forsyth 	Of		= 0x00000001,	/* Rx: OverFlow */
125*74a4d8c2SCharles.Forsyth 	Ce		= 0x00000002,	/* Rx: CRC Error */
126*74a4d8c2SCharles.Forsyth 	Db		= 0x00000004,	/* Rx: Dribbling Bit */
127*74a4d8c2SCharles.Forsyth 	Re		= 0x00000008,	/* Rx: Report on MII Error */
128*74a4d8c2SCharles.Forsyth 	Rw		= 0x00000010,	/* Rx: Receive Watchdog */
129*74a4d8c2SCharles.Forsyth 	Ft		= 0x00000020,	/* Rx: Frame Type */
130*74a4d8c2SCharles.Forsyth 	Cs		= 0x00000040,	/* Rx: Collision Seen */
131*74a4d8c2SCharles.Forsyth 	Tl		= 0x00000080,	/* Rx: Frame too Long */
132*74a4d8c2SCharles.Forsyth 	Ls		= 0x00000100,	/* Rx: Last deScriptor */
133*74a4d8c2SCharles.Forsyth 	Fs		= 0x00000200,	/* Rx: First deScriptor */
134*74a4d8c2SCharles.Forsyth 	Mf		= 0x00000400,	/* Rx: Multicast Frame */
135*74a4d8c2SCharles.Forsyth 	Rf		= 0x00000800,	/* Rx: Runt Frame */
136*74a4d8c2SCharles.Forsyth 	Dt		= 0x00003000,	/* Rx: Data Type (field) */
137*74a4d8c2SCharles.Forsyth 	De		= 0x00004000,	/* Rx: Descriptor Error */
138*74a4d8c2SCharles.Forsyth 	Fl		= 0x3FFF0000,	/* Rx: Frame Length (field) */
139*74a4d8c2SCharles.Forsyth 	Ff		= 0x40000000,	/* Rx: Filtering Fail */
140*74a4d8c2SCharles.Forsyth 
141*74a4d8c2SCharles.Forsyth 	Def		= 0x00000001,	/* Tx: DEFerred */
142*74a4d8c2SCharles.Forsyth 	Uf		= 0x00000002,	/* Tx: UnderFlow error */
143*74a4d8c2SCharles.Forsyth 	Lf		= 0x00000004,	/* Tx: Link Fail report */
144*74a4d8c2SCharles.Forsyth 	Cc		= 0x00000078,	/* Tx: Collision Count (field) */
145*74a4d8c2SCharles.Forsyth 	Hf		= 0x00000080,	/* Tx: Heartbeat Fail */
146*74a4d8c2SCharles.Forsyth 	Ec		= 0x00000100,	/* Tx: Excessive Collisions */
147*74a4d8c2SCharles.Forsyth 	Lc		= 0x00000200,	/* Tx: Late Collision */
148*74a4d8c2SCharles.Forsyth 	Nc		= 0x00000400,	/* Tx: No Carrier */
149*74a4d8c2SCharles.Forsyth 	Lo		= 0x00000800,	/* Tx: LOss of carrier */
150*74a4d8c2SCharles.Forsyth 	To		= 0x00004000,	/* Tx: Transmission jabber timeOut */
151*74a4d8c2SCharles.Forsyth 
152*74a4d8c2SCharles.Forsyth 	Es		= 0x00008000,	/* [RT]x: Error Summary */
153*74a4d8c2SCharles.Forsyth 	Own		= 0x80000000,	/* [RT]x: OWN bit */
154*74a4d8c2SCharles.Forsyth };
155*74a4d8c2SCharles.Forsyth 
156*74a4d8c2SCharles.Forsyth enum {					/* control */
157*74a4d8c2SCharles.Forsyth 	Bs1		= 0x000007FF,	/* [RT]x: Buffer 1 Size */
158*74a4d8c2SCharles.Forsyth 	Bs2		= 0x003FF800,	/* [RT]x: Buffer 2 Size */
159*74a4d8c2SCharles.Forsyth 
160*74a4d8c2SCharles.Forsyth 	Ch		= 0x01000000,	/* [RT]x: second address CHained */
161*74a4d8c2SCharles.Forsyth 	Er		= 0x02000000,	/* [RT]x: End of Ring */
162*74a4d8c2SCharles.Forsyth 
163*74a4d8c2SCharles.Forsyth 	Ft0		= 0x00400000,	/* Tx: Filtering Type 0 */
164*74a4d8c2SCharles.Forsyth 	Dpd		= 0x00800000,	/* Tx: Disabled PaDding */
165*74a4d8c2SCharles.Forsyth 	Ac		= 0x04000000,	/* Tx: Add CRC disable */
166*74a4d8c2SCharles.Forsyth 	Set		= 0x08000000,	/* Tx: SETup packet */
167*74a4d8c2SCharles.Forsyth 	Ft1		= 0x10000000,	/* Tx: Filtering Type 1 */
168*74a4d8c2SCharles.Forsyth 	Fseg		= 0x20000000,	/* Tx: First SEGment */
169*74a4d8c2SCharles.Forsyth 	Lseg		= 0x40000000,	/* Tx: Last SEGment */
170*74a4d8c2SCharles.Forsyth 	Ic		= 0x80000000,	/* Tx: Interrupt on Completion */
171*74a4d8c2SCharles.Forsyth };
172*74a4d8c2SCharles.Forsyth 
173*74a4d8c2SCharles.Forsyth enum {					/* PHY registers */
174*74a4d8c2SCharles.Forsyth 	Bmcr		= 0,		/* Basic Mode Control */
175*74a4d8c2SCharles.Forsyth 	Bmsr		= 1,		/* Basic Mode Status */
176*74a4d8c2SCharles.Forsyth 	Phyidr1		= 2,		/* PHY Identifier #1 */
177*74a4d8c2SCharles.Forsyth 	Phyidr2		= 3,		/* PHY Identifier #2 */
178*74a4d8c2SCharles.Forsyth 	Anar		= 4,		/* Auto-Negotiation Advertisment */
179*74a4d8c2SCharles.Forsyth 	Anlpar		= 5,		/* Auto-Negotiation Link Partner Ability */
180*74a4d8c2SCharles.Forsyth 	Aner		= 6,		/* Auto-Negotiation Expansion */
181*74a4d8c2SCharles.Forsyth };
182*74a4d8c2SCharles.Forsyth 
183*74a4d8c2SCharles.Forsyth enum {					/* Variants */
184*74a4d8c2SCharles.Forsyth 	Tulip0		= (0x0009<<16)|0x1011,
185*74a4d8c2SCharles.Forsyth 	Tulip1		= (0x0014<<16)|0x1011,
186*74a4d8c2SCharles.Forsyth 	Tulip3		= (0x0019<<16)|0x1011,
187*74a4d8c2SCharles.Forsyth 	Pnic		= (0x0002<<16)|0x11AD,
188*74a4d8c2SCharles.Forsyth 	Pnic2		= (0xC115<<16)|0x11AD,
189*74a4d8c2SCharles.Forsyth };
190*74a4d8c2SCharles.Forsyth 
191*74a4d8c2SCharles.Forsyth typedef struct Ctlr Ctlr;
192*74a4d8c2SCharles.Forsyth typedef struct Ctlr {
193*74a4d8c2SCharles.Forsyth 	int	port;
194*74a4d8c2SCharles.Forsyth 	Pcidev*	pcidev;
195*74a4d8c2SCharles.Forsyth 	Ctlr*	next;
196*74a4d8c2SCharles.Forsyth 	int	active;
197*74a4d8c2SCharles.Forsyth 	int	id;			/* (pcidev->did<<16)|pcidev->vid */
198*74a4d8c2SCharles.Forsyth 
199*74a4d8c2SCharles.Forsyth 	uchar	*srom;
200*74a4d8c2SCharles.Forsyth 	int	sromsz;
201*74a4d8c2SCharles.Forsyth 	uchar*	sromea;			/* MAC address */
202*74a4d8c2SCharles.Forsyth 	uchar*	leaf;
203*74a4d8c2SCharles.Forsyth 	int	sct;			/* selected connection type */
204*74a4d8c2SCharles.Forsyth 	int	k;			/* info block count */
205*74a4d8c2SCharles.Forsyth 	uchar*	infoblock[16];
206*74a4d8c2SCharles.Forsyth 	int	sctk;			/* sct block index */
207*74a4d8c2SCharles.Forsyth 	int	curk;			/* current block index */
208*74a4d8c2SCharles.Forsyth 	uchar*	type5block;
209*74a4d8c2SCharles.Forsyth 
210*74a4d8c2SCharles.Forsyth 	int	phy[32];		/* logical to physical map */
211*74a4d8c2SCharles.Forsyth 	int	phyreset;		/* reset bitmap */
212*74a4d8c2SCharles.Forsyth 	int	curphyad;
213*74a4d8c2SCharles.Forsyth 	int	fdx;
214*74a4d8c2SCharles.Forsyth 	int	ttm;
215*74a4d8c2SCharles.Forsyth 
216*74a4d8c2SCharles.Forsyth 	uchar	fd;			/* option */
217*74a4d8c2SCharles.Forsyth 	int	medium;			/* option */
218*74a4d8c2SCharles.Forsyth 
219*74a4d8c2SCharles.Forsyth 	int	csr6;			/* CSR6 - operating mode */
220*74a4d8c2SCharles.Forsyth 	int	mask;			/* CSR[57] - interrupt mask */
221*74a4d8c2SCharles.Forsyth 	int	mbps;
222*74a4d8c2SCharles.Forsyth 
223*74a4d8c2SCharles.Forsyth 	Des*	rdr;			/* receive descriptor ring */
224*74a4d8c2SCharles.Forsyth 	int	nrdr;			/* size of rdr */
225*74a4d8c2SCharles.Forsyth 	int	rdrx;			/* index into rdr */
226*74a4d8c2SCharles.Forsyth 
227*74a4d8c2SCharles.Forsyth 	Des*	tdr;			/* transmit descriptor ring */
228*74a4d8c2SCharles.Forsyth 	int	ntdr;			/* size of tdr */
229*74a4d8c2SCharles.Forsyth 	int	tdrh;			/* host index into tdr */
230*74a4d8c2SCharles.Forsyth 	int	tdri;			/* interface index into tdr */
231*74a4d8c2SCharles.Forsyth 	int	ntq;			/* descriptors active */
232*74a4d8c2SCharles.Forsyth 	Block*	setupbp;
233*74a4d8c2SCharles.Forsyth 
234*74a4d8c2SCharles.Forsyth 	ulong	of;			/* receive statistics */
235*74a4d8c2SCharles.Forsyth 	ulong	ce;
236*74a4d8c2SCharles.Forsyth 	ulong	cs;
237*74a4d8c2SCharles.Forsyth 	ulong	tl;
238*74a4d8c2SCharles.Forsyth 	ulong	rf;
239*74a4d8c2SCharles.Forsyth 	ulong	de;
240*74a4d8c2SCharles.Forsyth 
241*74a4d8c2SCharles.Forsyth 	ulong	uf;			/* transmit statistics */
242*74a4d8c2SCharles.Forsyth 	ulong	ec;
243*74a4d8c2SCharles.Forsyth 	ulong	lc;
244*74a4d8c2SCharles.Forsyth 	ulong	nc;
245*74a4d8c2SCharles.Forsyth 	ulong	lo;
246*74a4d8c2SCharles.Forsyth 	ulong	to;
247*74a4d8c2SCharles.Forsyth 
248*74a4d8c2SCharles.Forsyth } Ctlr;
249*74a4d8c2SCharles.Forsyth 
250*74a4d8c2SCharles.Forsyth static Ctlr* ctlrhead;
251*74a4d8c2SCharles.Forsyth static Ctlr* ctlrtail;
252*74a4d8c2SCharles.Forsyth 
253*74a4d8c2SCharles.Forsyth #define csr32r(c, r)	(inl((c)->port+((r)*8)))
254*74a4d8c2SCharles.Forsyth #define csr32w(c, r, l)	(outl((c)->port+((r)*8), (ulong)(l)))
255*74a4d8c2SCharles.Forsyth 
256*74a4d8c2SCharles.Forsyth static void
attach(Ether * ether)257*74a4d8c2SCharles.Forsyth attach(Ether* ether)
258*74a4d8c2SCharles.Forsyth {
259*74a4d8c2SCharles.Forsyth 	Ctlr *ctlr;
260*74a4d8c2SCharles.Forsyth 
261*74a4d8c2SCharles.Forsyth 	ctlr = ether->ctlr;
262*74a4d8c2SCharles.Forsyth 	if(!(ctlr->csr6 & Sr)){
263*74a4d8c2SCharles.Forsyth 		ctlr->csr6 |= Sr;
264*74a4d8c2SCharles.Forsyth 		csr32w(ctlr, 6, ctlr->csr6);
265*74a4d8c2SCharles.Forsyth 	}
266*74a4d8c2SCharles.Forsyth }
267*74a4d8c2SCharles.Forsyth 
268*74a4d8c2SCharles.Forsyth static void
transmit(Ether * ether)269*74a4d8c2SCharles.Forsyth transmit(Ether* ether)
270*74a4d8c2SCharles.Forsyth {
271*74a4d8c2SCharles.Forsyth 	Ctlr *ctlr;
272*74a4d8c2SCharles.Forsyth 	Block *bp;
273*74a4d8c2SCharles.Forsyth 	Des *des;
274*74a4d8c2SCharles.Forsyth 	int control;
275*74a4d8c2SCharles.Forsyth 	RingBuf *tb;
276*74a4d8c2SCharles.Forsyth 
277*74a4d8c2SCharles.Forsyth 	ctlr = ether->ctlr;
278*74a4d8c2SCharles.Forsyth 	while(ctlr->ntq < (ctlr->ntdr-1)){
279*74a4d8c2SCharles.Forsyth 		if(ctlr->setupbp){
280*74a4d8c2SCharles.Forsyth 			bp = ctlr->setupbp;
281*74a4d8c2SCharles.Forsyth 			ctlr->setupbp = 0;
282*74a4d8c2SCharles.Forsyth 			control = Ic|Set|BLEN(bp);
283*74a4d8c2SCharles.Forsyth 		}
284*74a4d8c2SCharles.Forsyth 		else{
285*74a4d8c2SCharles.Forsyth 			if(ether->ntb == 0)
286*74a4d8c2SCharles.Forsyth 				break;
287*74a4d8c2SCharles.Forsyth 			tb = &ether->tb[ether->ti];
288*74a4d8c2SCharles.Forsyth 			if(tb->owner != Interface)
289*74a4d8c2SCharles.Forsyth 				break;
290*74a4d8c2SCharles.Forsyth 			bp = allocb(tb->len);
291*74a4d8c2SCharles.Forsyth 			memmove(bp->wp, tb->pkt, tb->len);
292*74a4d8c2SCharles.Forsyth 			memmove(bp->wp+Eaddrlen, ether->ea, Eaddrlen);
293*74a4d8c2SCharles.Forsyth 			bp->wp += tb->len;
294*74a4d8c2SCharles.Forsyth 
295*74a4d8c2SCharles.Forsyth 			tb->owner = Host;
296*74a4d8c2SCharles.Forsyth 			ether->ti = NEXT(ether->ti, ether->ntb);
297*74a4d8c2SCharles.Forsyth 
298*74a4d8c2SCharles.Forsyth 			control = Ic|Lseg|Fseg|BLEN(bp);
299*74a4d8c2SCharles.Forsyth 		}
300*74a4d8c2SCharles.Forsyth 
301*74a4d8c2SCharles.Forsyth 		ctlr->tdr[PREV(ctlr->tdrh, ctlr->ntdr)].control &= ~Ic;
302*74a4d8c2SCharles.Forsyth 		des = &ctlr->tdr[ctlr->tdrh];
303*74a4d8c2SCharles.Forsyth 		des->bp = bp;
304*74a4d8c2SCharles.Forsyth 		des->addr = PADDR(bp->rp);
305*74a4d8c2SCharles.Forsyth 		des->control |= control;
306*74a4d8c2SCharles.Forsyth 		ctlr->ntq++;
307*74a4d8c2SCharles.Forsyth 		//coherence();
308*74a4d8c2SCharles.Forsyth 		des->status = Own;
309*74a4d8c2SCharles.Forsyth 		csr32w(ctlr, 1, 0);
310*74a4d8c2SCharles.Forsyth 		ctlr->tdrh = NEXT(ctlr->tdrh, ctlr->ntdr);
311*74a4d8c2SCharles.Forsyth 	}
312*74a4d8c2SCharles.Forsyth }
313*74a4d8c2SCharles.Forsyth 
314*74a4d8c2SCharles.Forsyth static void
interrupt(Ureg *,void * arg)315*74a4d8c2SCharles.Forsyth interrupt(Ureg*, void* arg)
316*74a4d8c2SCharles.Forsyth {
317*74a4d8c2SCharles.Forsyth 	Ctlr *ctlr;
318*74a4d8c2SCharles.Forsyth 	Ether *ether;
319*74a4d8c2SCharles.Forsyth 	int len, status;
320*74a4d8c2SCharles.Forsyth 	Des *des;
321*74a4d8c2SCharles.Forsyth 	RingBuf *ring;
322*74a4d8c2SCharles.Forsyth 
323*74a4d8c2SCharles.Forsyth 	ether = arg;
324*74a4d8c2SCharles.Forsyth 	ctlr = ether->ctlr;
325*74a4d8c2SCharles.Forsyth 
326*74a4d8c2SCharles.Forsyth 	while((status = csr32r(ctlr, 5)) & (Nis|Ais)){
327*74a4d8c2SCharles.Forsyth 		/*
328*74a4d8c2SCharles.Forsyth 		 * Acknowledge the interrupts and mask-out
329*74a4d8c2SCharles.Forsyth 		 * the ones that are implicitly handled.
330*74a4d8c2SCharles.Forsyth 		 */
331*74a4d8c2SCharles.Forsyth 		csr32w(ctlr, 5, status);
332*74a4d8c2SCharles.Forsyth 		status &= (ctlr->mask & ~(Nis|Ais|Ti));
333*74a4d8c2SCharles.Forsyth 
334*74a4d8c2SCharles.Forsyth 		/*
335*74a4d8c2SCharles.Forsyth 		 * Received packets.
336*74a4d8c2SCharles.Forsyth 		 */
337*74a4d8c2SCharles.Forsyth 		if(status & Ri){
338*74a4d8c2SCharles.Forsyth 			des = &ctlr->rdr[ctlr->rdrx];
339*74a4d8c2SCharles.Forsyth 			while((des->status & Own) == 0){
340*74a4d8c2SCharles.Forsyth 				len = ((des->status & Fl)>>16)-4;
341*74a4d8c2SCharles.Forsyth 				if(des->status & Es){
342*74a4d8c2SCharles.Forsyth 					if(des->status & Of)
343*74a4d8c2SCharles.Forsyth 						ctlr->of++;
344*74a4d8c2SCharles.Forsyth 					if(des->status & Ce)
345*74a4d8c2SCharles.Forsyth 						ctlr->ce++;
346*74a4d8c2SCharles.Forsyth 					if(des->status & Cs)
347*74a4d8c2SCharles.Forsyth 						ctlr->cs++;
348*74a4d8c2SCharles.Forsyth 					if(des->status & Tl)
349*74a4d8c2SCharles.Forsyth 						ctlr->tl++;
350*74a4d8c2SCharles.Forsyth 					if(des->status & Rf)
351*74a4d8c2SCharles.Forsyth 						ctlr->rf++;
352*74a4d8c2SCharles.Forsyth 					if(des->status & De)
353*74a4d8c2SCharles.Forsyth 						ctlr->de++;
354*74a4d8c2SCharles.Forsyth 				}
355*74a4d8c2SCharles.Forsyth 				else{
356*74a4d8c2SCharles.Forsyth 					ring = &ether->rb[ether->ri];
357*74a4d8c2SCharles.Forsyth 					if(ring->owner == Interface){
358*74a4d8c2SCharles.Forsyth 						ring->owner = Host;
359*74a4d8c2SCharles.Forsyth 						ring->len = len;
360*74a4d8c2SCharles.Forsyth 						memmove(ring->pkt, des->bp, len);
361*74a4d8c2SCharles.Forsyth 						ether->ri = NEXT(ether->ri, ether->nrb);
362*74a4d8c2SCharles.Forsyth 					}
363*74a4d8c2SCharles.Forsyth 				}
364*74a4d8c2SCharles.Forsyth 
365*74a4d8c2SCharles.Forsyth 				des->control &= Er;
366*74a4d8c2SCharles.Forsyth 				des->control |= Rbsz;
367*74a4d8c2SCharles.Forsyth 				des->status = Own;
368*74a4d8c2SCharles.Forsyth 
369*74a4d8c2SCharles.Forsyth 				ctlr->rdrx = NEXT(ctlr->rdrx, ctlr->nrdr);
370*74a4d8c2SCharles.Forsyth 				des = &ctlr->rdr[ctlr->rdrx];
371*74a4d8c2SCharles.Forsyth 			}
372*74a4d8c2SCharles.Forsyth 			status &= ~Ri;
373*74a4d8c2SCharles.Forsyth 		}
374*74a4d8c2SCharles.Forsyth 
375*74a4d8c2SCharles.Forsyth 		/*
376*74a4d8c2SCharles.Forsyth 		 * Check the transmit side:
377*74a4d8c2SCharles.Forsyth 		 *	check for Transmit Underflow and Adjust
378*74a4d8c2SCharles.Forsyth 		 *	the threshold upwards;
379*74a4d8c2SCharles.Forsyth 		 *	free any transmitted buffers and try to
380*74a4d8c2SCharles.Forsyth 		 *	top-up the ring.
381*74a4d8c2SCharles.Forsyth 		 */
382*74a4d8c2SCharles.Forsyth 		if(status & Unf){
383*74a4d8c2SCharles.Forsyth 			csr32w(ctlr, 6, ctlr->csr6 & ~St);
384*74a4d8c2SCharles.Forsyth 			switch(ctlr->csr6 & Tr){
385*74a4d8c2SCharles.Forsyth 			case Tr128:
386*74a4d8c2SCharles.Forsyth 				len = Tr256;
387*74a4d8c2SCharles.Forsyth 				break;
388*74a4d8c2SCharles.Forsyth 			case Tr256:
389*74a4d8c2SCharles.Forsyth 				len = Tr512;
390*74a4d8c2SCharles.Forsyth 				break;
391*74a4d8c2SCharles.Forsyth 			case Tr512:
392*74a4d8c2SCharles.Forsyth 				len = Tr1024;
393*74a4d8c2SCharles.Forsyth 				break;
394*74a4d8c2SCharles.Forsyth 			default:
395*74a4d8c2SCharles.Forsyth 			case Tr1024:
396*74a4d8c2SCharles.Forsyth 				len = Sf;
397*74a4d8c2SCharles.Forsyth 				break;
398*74a4d8c2SCharles.Forsyth 			}
399*74a4d8c2SCharles.Forsyth 			ctlr->csr6 = (ctlr->csr6 & ~Tr)|len;
400*74a4d8c2SCharles.Forsyth 			csr32w(ctlr, 6, ctlr->csr6);
401*74a4d8c2SCharles.Forsyth 			csr32w(ctlr, 5, Tps);
402*74a4d8c2SCharles.Forsyth 			status &= ~(Unf|Tps);
403*74a4d8c2SCharles.Forsyth 		}
404*74a4d8c2SCharles.Forsyth 
405*74a4d8c2SCharles.Forsyth 		while(ctlr->ntq){
406*74a4d8c2SCharles.Forsyth 			des = &ctlr->tdr[ctlr->tdri];
407*74a4d8c2SCharles.Forsyth 			if(des->status & Own)
408*74a4d8c2SCharles.Forsyth 				break;
409*74a4d8c2SCharles.Forsyth 
410*74a4d8c2SCharles.Forsyth 			if(des->status & Es){
411*74a4d8c2SCharles.Forsyth 				if(des->status & Uf)
412*74a4d8c2SCharles.Forsyth 					ctlr->uf++;
413*74a4d8c2SCharles.Forsyth 				if(des->status & Ec)
414*74a4d8c2SCharles.Forsyth 					ctlr->ec++;
415*74a4d8c2SCharles.Forsyth 				if(des->status & Lc)
416*74a4d8c2SCharles.Forsyth 					ctlr->lc++;
417*74a4d8c2SCharles.Forsyth 				if(des->status & Nc)
418*74a4d8c2SCharles.Forsyth 					ctlr->nc++;
419*74a4d8c2SCharles.Forsyth 				if(des->status & Lo)
420*74a4d8c2SCharles.Forsyth 					ctlr->lo++;
421*74a4d8c2SCharles.Forsyth 				if(des->status & To)
422*74a4d8c2SCharles.Forsyth 					ctlr->to++;
423*74a4d8c2SCharles.Forsyth 			}
424*74a4d8c2SCharles.Forsyth 
425*74a4d8c2SCharles.Forsyth 			freeb(des->bp);
426*74a4d8c2SCharles.Forsyth 			des->control &= Er;
427*74a4d8c2SCharles.Forsyth 
428*74a4d8c2SCharles.Forsyth 			ctlr->ntq--;
429*74a4d8c2SCharles.Forsyth 			ctlr->tdri = NEXT(ctlr->tdri, ctlr->ntdr);
430*74a4d8c2SCharles.Forsyth 		}
431*74a4d8c2SCharles.Forsyth 		transmit(ether);
432*74a4d8c2SCharles.Forsyth 
433*74a4d8c2SCharles.Forsyth 		/*
434*74a4d8c2SCharles.Forsyth 		 * Anything left not catered for?
435*74a4d8c2SCharles.Forsyth 		 */
436*74a4d8c2SCharles.Forsyth 		if(status)
437*74a4d8c2SCharles.Forsyth 			panic("#l%d: status %8.8uX\n", ether->ctlrno, status);
438*74a4d8c2SCharles.Forsyth 	}
439*74a4d8c2SCharles.Forsyth }
440*74a4d8c2SCharles.Forsyth 
441*74a4d8c2SCharles.Forsyth static void
ctlrinit(Ether * ether)442*74a4d8c2SCharles.Forsyth ctlrinit(Ether* ether)
443*74a4d8c2SCharles.Forsyth {
444*74a4d8c2SCharles.Forsyth 	Ctlr *ctlr;
445*74a4d8c2SCharles.Forsyth 	Des *des;
446*74a4d8c2SCharles.Forsyth 	Block *bp;
447*74a4d8c2SCharles.Forsyth 	int i;
448*74a4d8c2SCharles.Forsyth 	uchar bi[Eaddrlen*2];
449*74a4d8c2SCharles.Forsyth 
450*74a4d8c2SCharles.Forsyth 	ctlr = ether->ctlr;
451*74a4d8c2SCharles.Forsyth 
452*74a4d8c2SCharles.Forsyth 	/*
453*74a4d8c2SCharles.Forsyth 	 * Allocate and initialise the receive ring;
454*74a4d8c2SCharles.Forsyth 	 * allocate and initialise the transmit ring;
455*74a4d8c2SCharles.Forsyth 	 * unmask interrupts and start the transmit side;
456*74a4d8c2SCharles.Forsyth 	 * create and post a setup packet to initialise
457*74a4d8c2SCharles.Forsyth 	 * the physical ethernet address.
458*74a4d8c2SCharles.Forsyth 	 */
459*74a4d8c2SCharles.Forsyth 	ctlr->rdr = malloc(ctlr->nrdr*sizeof(Des));
460*74a4d8c2SCharles.Forsyth 	for(des = ctlr->rdr; des < &ctlr->rdr[ctlr->nrdr]; des++){
461*74a4d8c2SCharles.Forsyth 		des->bp = malloc(Rbsz);
462*74a4d8c2SCharles.Forsyth 		des->status = Own;
463*74a4d8c2SCharles.Forsyth 		des->control = Rbsz;
464*74a4d8c2SCharles.Forsyth 		des->addr = PADDR(des->bp);
465*74a4d8c2SCharles.Forsyth 	}
466*74a4d8c2SCharles.Forsyth 	ctlr->rdr[ctlr->nrdr-1].control |= Er;
467*74a4d8c2SCharles.Forsyth 	ctlr->rdrx = 0;
468*74a4d8c2SCharles.Forsyth 	csr32w(ctlr, 3, PADDR(ctlr->rdr));
469*74a4d8c2SCharles.Forsyth 
470*74a4d8c2SCharles.Forsyth 	ctlr->tdr = ialloc(ctlr->ntdr*sizeof(Des), 32);
471*74a4d8c2SCharles.Forsyth 	ctlr->tdr[ctlr->ntdr-1].control |= Er;
472*74a4d8c2SCharles.Forsyth 	ctlr->tdrh = 0;
473*74a4d8c2SCharles.Forsyth 	ctlr->tdri = 0;
474*74a4d8c2SCharles.Forsyth 	csr32w(ctlr, 4, PADDR(ctlr->tdr));
475*74a4d8c2SCharles.Forsyth 
476*74a4d8c2SCharles.Forsyth 	/*
477*74a4d8c2SCharles.Forsyth 	 * Clear any bits in the Status Register (CSR5) as
478*74a4d8c2SCharles.Forsyth 	 * the PNIC has a different reset value from a true 2114x.
479*74a4d8c2SCharles.Forsyth 	 */
480*74a4d8c2SCharles.Forsyth 	ctlr->mask = Nis|Ais|Fbe|Rwt|Rps|Ru|Ri|Unf|Tjt|Tps|Ti;
481*74a4d8c2SCharles.Forsyth 	csr32w(ctlr, 5, ctlr->mask);
482*74a4d8c2SCharles.Forsyth 	csr32w(ctlr, 7, ctlr->mask);
483*74a4d8c2SCharles.Forsyth 	ctlr->csr6 |= St;
484*74a4d8c2SCharles.Forsyth 	csr32w(ctlr, 6, ctlr->csr6);
485*74a4d8c2SCharles.Forsyth 
486*74a4d8c2SCharles.Forsyth 	for(i = 0; i < Eaddrlen/2; i++){
487*74a4d8c2SCharles.Forsyth 		bi[i*4] = ether->ea[i*2];
488*74a4d8c2SCharles.Forsyth 		bi[i*4+1] = ether->ea[i*2+1];
489*74a4d8c2SCharles.Forsyth 		bi[i*4+2] = ether->ea[i*2+1];
490*74a4d8c2SCharles.Forsyth 		bi[i*4+3] = ether->ea[i*2];
491*74a4d8c2SCharles.Forsyth 	}
492*74a4d8c2SCharles.Forsyth 	bp = allocb(Eaddrlen*2*16);
493*74a4d8c2SCharles.Forsyth 	memset(bp->rp, 0xFF, sizeof(bi));
494*74a4d8c2SCharles.Forsyth 	for(i = sizeof(bi); i < sizeof(bi)*16; i += sizeof(bi))
495*74a4d8c2SCharles.Forsyth 		memmove(bp->rp+i, bi, sizeof(bi));
496*74a4d8c2SCharles.Forsyth 	bp->wp += sizeof(bi)*16;
497*74a4d8c2SCharles.Forsyth 
498*74a4d8c2SCharles.Forsyth 	ctlr->setupbp = bp;
499*74a4d8c2SCharles.Forsyth 	transmit(ether);
500*74a4d8c2SCharles.Forsyth }
501*74a4d8c2SCharles.Forsyth 
502*74a4d8c2SCharles.Forsyth static void
csr9w(Ctlr * ctlr,int data)503*74a4d8c2SCharles.Forsyth csr9w(Ctlr* ctlr, int data)
504*74a4d8c2SCharles.Forsyth {
505*74a4d8c2SCharles.Forsyth 	csr32w(ctlr, 9, data);
506*74a4d8c2SCharles.Forsyth 	microdelay(1);
507*74a4d8c2SCharles.Forsyth }
508*74a4d8c2SCharles.Forsyth 
509*74a4d8c2SCharles.Forsyth static int
miimdi(Ctlr * ctlr,int n)510*74a4d8c2SCharles.Forsyth miimdi(Ctlr* ctlr, int n)
511*74a4d8c2SCharles.Forsyth {
512*74a4d8c2SCharles.Forsyth 	int data, i;
513*74a4d8c2SCharles.Forsyth 
514*74a4d8c2SCharles.Forsyth 	/*
515*74a4d8c2SCharles.Forsyth 	 * Read n bits from the MII Management Register.
516*74a4d8c2SCharles.Forsyth 	 */
517*74a4d8c2SCharles.Forsyth 	data = 0;
518*74a4d8c2SCharles.Forsyth 	for(i = n-1; i >= 0; i--){
519*74a4d8c2SCharles.Forsyth 		if(csr32r(ctlr, 9) & Mdi)
520*74a4d8c2SCharles.Forsyth 			data |= (1<<i);
521*74a4d8c2SCharles.Forsyth 		csr9w(ctlr, Mii|Mdc);
522*74a4d8c2SCharles.Forsyth 		csr9w(ctlr, Mii);
523*74a4d8c2SCharles.Forsyth 	}
524*74a4d8c2SCharles.Forsyth 	csr9w(ctlr, 0);
525*74a4d8c2SCharles.Forsyth 
526*74a4d8c2SCharles.Forsyth 	return data;
527*74a4d8c2SCharles.Forsyth }
528*74a4d8c2SCharles.Forsyth 
529*74a4d8c2SCharles.Forsyth static void
miimdo(Ctlr * ctlr,int bits,int n)530*74a4d8c2SCharles.Forsyth miimdo(Ctlr* ctlr, int bits, int n)
531*74a4d8c2SCharles.Forsyth {
532*74a4d8c2SCharles.Forsyth 	int i, mdo;
533*74a4d8c2SCharles.Forsyth 
534*74a4d8c2SCharles.Forsyth 	/*
535*74a4d8c2SCharles.Forsyth 	 * Write n bits to the MII Management Register.
536*74a4d8c2SCharles.Forsyth 	 */
537*74a4d8c2SCharles.Forsyth 	for(i = n-1; i >= 0; i--){
538*74a4d8c2SCharles.Forsyth 		if(bits & (1<<i))
539*74a4d8c2SCharles.Forsyth 			mdo = Mdo;
540*74a4d8c2SCharles.Forsyth 		else
541*74a4d8c2SCharles.Forsyth 			mdo = 0;
542*74a4d8c2SCharles.Forsyth 		csr9w(ctlr, mdo);
543*74a4d8c2SCharles.Forsyth 		csr9w(ctlr, mdo|Mdc);
544*74a4d8c2SCharles.Forsyth 		csr9w(ctlr, mdo);
545*74a4d8c2SCharles.Forsyth 	}
546*74a4d8c2SCharles.Forsyth }
547*74a4d8c2SCharles.Forsyth 
548*74a4d8c2SCharles.Forsyth static int
miir(Ctlr * ctlr,int phyad,int regad)549*74a4d8c2SCharles.Forsyth miir(Ctlr* ctlr, int phyad, int regad)
550*74a4d8c2SCharles.Forsyth {
551*74a4d8c2SCharles.Forsyth 	int data, i;
552*74a4d8c2SCharles.Forsyth 
553*74a4d8c2SCharles.Forsyth 	if(ctlr->id == Pnic){
554*74a4d8c2SCharles.Forsyth 		i = 1000;
555*74a4d8c2SCharles.Forsyth 		csr32w(ctlr, 20, 0x60020000|(phyad<<23)|(regad<<18));
556*74a4d8c2SCharles.Forsyth 		do{
557*74a4d8c2SCharles.Forsyth 			microdelay(1);
558*74a4d8c2SCharles.Forsyth 			data = csr32r(ctlr, 20);
559*74a4d8c2SCharles.Forsyth 		}while((data & 0x80000000) && --i);
560*74a4d8c2SCharles.Forsyth 
561*74a4d8c2SCharles.Forsyth 		if(i == 0)
562*74a4d8c2SCharles.Forsyth 			return -1;
563*74a4d8c2SCharles.Forsyth 		return data & 0xFFFF;
564*74a4d8c2SCharles.Forsyth 	}
565*74a4d8c2SCharles.Forsyth 
566*74a4d8c2SCharles.Forsyth 	/*
567*74a4d8c2SCharles.Forsyth 	 * Preamble;
568*74a4d8c2SCharles.Forsyth 	 * ST+OP+PHYAD+REGAD;
569*74a4d8c2SCharles.Forsyth 	 * TA + 16 data bits.
570*74a4d8c2SCharles.Forsyth 	 */
571*74a4d8c2SCharles.Forsyth 	miimdo(ctlr, 0xFFFFFFFF, 32);
572*74a4d8c2SCharles.Forsyth 	miimdo(ctlr, 0x1800|(phyad<<5)|regad, 14);
573*74a4d8c2SCharles.Forsyth 	data = miimdi(ctlr, 18);
574*74a4d8c2SCharles.Forsyth 
575*74a4d8c2SCharles.Forsyth 	if(data & 0x10000)
576*74a4d8c2SCharles.Forsyth 		return -1;
577*74a4d8c2SCharles.Forsyth 
578*74a4d8c2SCharles.Forsyth 	return data & 0xFFFF;
579*74a4d8c2SCharles.Forsyth }
580*74a4d8c2SCharles.Forsyth 
581*74a4d8c2SCharles.Forsyth static void
miiw(Ctlr * ctlr,int phyad,int regad,int data)582*74a4d8c2SCharles.Forsyth miiw(Ctlr* ctlr, int phyad, int regad, int data)
583*74a4d8c2SCharles.Forsyth {
584*74a4d8c2SCharles.Forsyth 	/*
585*74a4d8c2SCharles.Forsyth 	 * Preamble;
586*74a4d8c2SCharles.Forsyth 	 * ST+OP+PHYAD+REGAD+TA + 16 data bits;
587*74a4d8c2SCharles.Forsyth 	 * Z.
588*74a4d8c2SCharles.Forsyth 	 */
589*74a4d8c2SCharles.Forsyth 	miimdo(ctlr, 0xFFFFFFFF, 32);
590*74a4d8c2SCharles.Forsyth 	data &= 0xFFFF;
591*74a4d8c2SCharles.Forsyth 	data |= (0x05<<(5+5+2+16))|(phyad<<(5+2+16))|(regad<<(2+16))|(0x02<<16);
592*74a4d8c2SCharles.Forsyth 	miimdo(ctlr, data, 32);
593*74a4d8c2SCharles.Forsyth 	csr9w(ctlr, Mdc);
594*74a4d8c2SCharles.Forsyth 	csr9w(ctlr, 0);
595*74a4d8c2SCharles.Forsyth }
596*74a4d8c2SCharles.Forsyth 
597*74a4d8c2SCharles.Forsyth static int
sromr(Ctlr * ctlr,int r)598*74a4d8c2SCharles.Forsyth sromr(Ctlr* ctlr, int r)
599*74a4d8c2SCharles.Forsyth {
600*74a4d8c2SCharles.Forsyth 	int i, op, data, size;
601*74a4d8c2SCharles.Forsyth 
602*74a4d8c2SCharles.Forsyth 	if(ctlr->id == Pnic){
603*74a4d8c2SCharles.Forsyth 		i = 1000;
604*74a4d8c2SCharles.Forsyth 		csr32w(ctlr, 19, 0x600|r);
605*74a4d8c2SCharles.Forsyth 		do{
606*74a4d8c2SCharles.Forsyth 			microdelay(1);
607*74a4d8c2SCharles.Forsyth 			data = csr32r(ctlr, 19);
608*74a4d8c2SCharles.Forsyth 		}while((data & 0x80000000) && --i);
609*74a4d8c2SCharles.Forsyth 
610*74a4d8c2SCharles.Forsyth 		if(ctlr->sromsz == 0)
611*74a4d8c2SCharles.Forsyth 			ctlr->sromsz = 6;
612*74a4d8c2SCharles.Forsyth 
613*74a4d8c2SCharles.Forsyth 		return csr32r(ctlr, 9) & 0xFFFF;
614*74a4d8c2SCharles.Forsyth 	}
615*74a4d8c2SCharles.Forsyth 
616*74a4d8c2SCharles.Forsyth 	/*
617*74a4d8c2SCharles.Forsyth 	 * This sequence for reading a 16-bit register 'r'
618*74a4d8c2SCharles.Forsyth 	 * in the EEPROM is taken (pretty much) straight from Section
619*74a4d8c2SCharles.Forsyth 	 * 7.4 of the 21140 Hardware Reference Manual.
620*74a4d8c2SCharles.Forsyth 	 */
621*74a4d8c2SCharles.Forsyth reread:
622*74a4d8c2SCharles.Forsyth 	csr9w(ctlr, Rd|Ss);
623*74a4d8c2SCharles.Forsyth 	csr9w(ctlr, Rd|Ss|Scs);
624*74a4d8c2SCharles.Forsyth 	csr9w(ctlr, Rd|Ss|Sclk|Scs);
625*74a4d8c2SCharles.Forsyth 	csr9w(ctlr, Rd|Ss);
626*74a4d8c2SCharles.Forsyth 
627*74a4d8c2SCharles.Forsyth 	op = 0x06;
628*74a4d8c2SCharles.Forsyth 	for(i = 3-1; i >= 0; i--){
629*74a4d8c2SCharles.Forsyth 		data = Rd|Ss|(((op>>i) & 0x01)<<2)|Scs;
630*74a4d8c2SCharles.Forsyth 		csr9w(ctlr, data);
631*74a4d8c2SCharles.Forsyth 		csr9w(ctlr, data|Sclk);
632*74a4d8c2SCharles.Forsyth 		csr9w(ctlr, data);
633*74a4d8c2SCharles.Forsyth 	}
634*74a4d8c2SCharles.Forsyth 
635*74a4d8c2SCharles.Forsyth 	/*
636*74a4d8c2SCharles.Forsyth 	 * First time through must work out the EEPROM size.
637*74a4d8c2SCharles.Forsyth 	 * This doesn't seem to work on the 21041 as implemented
638*74a4d8c2SCharles.Forsyth 	 * in Virtual PC for the Mac, so wire any 21041 to 6,
639*74a4d8c2SCharles.Forsyth 	 * it's the only 21041 this code will ever likely see.
640*74a4d8c2SCharles.Forsyth 	 */
641*74a4d8c2SCharles.Forsyth 	if((size = ctlr->sromsz) == 0){
642*74a4d8c2SCharles.Forsyth 		if(ctlr->id == Tulip1)
643*74a4d8c2SCharles.Forsyth 			ctlr->sromsz = size = 6;
644*74a4d8c2SCharles.Forsyth 		else
645*74a4d8c2SCharles.Forsyth 			size = 8;
646*74a4d8c2SCharles.Forsyth 	}
647*74a4d8c2SCharles.Forsyth 
648*74a4d8c2SCharles.Forsyth 	for(size = size-1; size >= 0; size--){
649*74a4d8c2SCharles.Forsyth 		data = Rd|Ss|(((r>>size) & 0x01)<<2)|Scs;
650*74a4d8c2SCharles.Forsyth 		csr9w(ctlr, data);
651*74a4d8c2SCharles.Forsyth 		csr9w(ctlr, data|Sclk);
652*74a4d8c2SCharles.Forsyth 		csr9w(ctlr, data);
653*74a4d8c2SCharles.Forsyth 		microdelay(1);
654*74a4d8c2SCharles.Forsyth 		if(ctlr->sromsz == 0 && !(csr32r(ctlr, 9) & Sdo))
655*74a4d8c2SCharles.Forsyth 			break;
656*74a4d8c2SCharles.Forsyth 	}
657*74a4d8c2SCharles.Forsyth 
658*74a4d8c2SCharles.Forsyth 	data = 0;
659*74a4d8c2SCharles.Forsyth 	for(i = 16-1; i >= 0; i--){
660*74a4d8c2SCharles.Forsyth 		csr9w(ctlr, Rd|Ss|Sclk|Scs);
661*74a4d8c2SCharles.Forsyth 		if(csr32r(ctlr, 9) & Sdo)
662*74a4d8c2SCharles.Forsyth 			data |= (1<<i);
663*74a4d8c2SCharles.Forsyth 		csr9w(ctlr, Rd|Ss|Scs);
664*74a4d8c2SCharles.Forsyth 	}
665*74a4d8c2SCharles.Forsyth 
666*74a4d8c2SCharles.Forsyth 	csr9w(ctlr, 0);
667*74a4d8c2SCharles.Forsyth 
668*74a4d8c2SCharles.Forsyth 	if(ctlr->sromsz == 0){
669*74a4d8c2SCharles.Forsyth 		ctlr->sromsz = 8-size;
670*74a4d8c2SCharles.Forsyth 		goto reread;
671*74a4d8c2SCharles.Forsyth 	}
672*74a4d8c2SCharles.Forsyth 
673*74a4d8c2SCharles.Forsyth 	return data & 0xFFFF;
674*74a4d8c2SCharles.Forsyth }
675*74a4d8c2SCharles.Forsyth 
676*74a4d8c2SCharles.Forsyth static void
softreset(Ctlr * ctlr)677*74a4d8c2SCharles.Forsyth softreset(Ctlr* ctlr)
678*74a4d8c2SCharles.Forsyth {
679*74a4d8c2SCharles.Forsyth 	/*
680*74a4d8c2SCharles.Forsyth 	 * Soft-reset the controller and initialise bus mode.
681*74a4d8c2SCharles.Forsyth 	 * Delay should be >= 50 PCI cycles (2×S @ 25MHz).
682*74a4d8c2SCharles.Forsyth 	 */
683*74a4d8c2SCharles.Forsyth 	csr32w(ctlr, 0, Swr);
684*74a4d8c2SCharles.Forsyth 	microdelay(10);
685*74a4d8c2SCharles.Forsyth 	csr32w(ctlr, 0, Rml|Cal16);
686*74a4d8c2SCharles.Forsyth 	delay(1);
687*74a4d8c2SCharles.Forsyth }
688*74a4d8c2SCharles.Forsyth 
689*74a4d8c2SCharles.Forsyth static int
type5block(Ctlr * ctlr,uchar * block)690*74a4d8c2SCharles.Forsyth type5block(Ctlr* ctlr, uchar* block)
691*74a4d8c2SCharles.Forsyth {
692*74a4d8c2SCharles.Forsyth 	int csr15, i, len;
693*74a4d8c2SCharles.Forsyth 
694*74a4d8c2SCharles.Forsyth 	/*
695*74a4d8c2SCharles.Forsyth 	 * Reset or GPR sequence. Reset should be once only,
696*74a4d8c2SCharles.Forsyth 	 * before the GPR sequence.
697*74a4d8c2SCharles.Forsyth 	 * Note 'block' is not a pointer to the block head but
698*74a4d8c2SCharles.Forsyth 	 * a pointer to the data in the block starting at the
699*74a4d8c2SCharles.Forsyth 	 * reset length value so type5block can be used for the
700*74a4d8c2SCharles.Forsyth 	 * sequences contained in type 1 and type 3 blocks.
701*74a4d8c2SCharles.Forsyth 	 * The SROM docs state the 21140 type 5 block is the
702*74a4d8c2SCharles.Forsyth 	 * same as that for the 21143, but the two controllers
703*74a4d8c2SCharles.Forsyth 	 * use different registers and sequence-element lengths
704*74a4d8c2SCharles.Forsyth 	 * so the 21140 code here is a guess for a real type 5
705*74a4d8c2SCharles.Forsyth 	 * sequence.
706*74a4d8c2SCharles.Forsyth 	 */
707*74a4d8c2SCharles.Forsyth 	len = *block++;
708*74a4d8c2SCharles.Forsyth 	if(ctlr->id != Tulip3){
709*74a4d8c2SCharles.Forsyth 		for(i = 0; i < len; i++){
710*74a4d8c2SCharles.Forsyth 			csr32w(ctlr, 12, *block);
711*74a4d8c2SCharles.Forsyth 			block++;
712*74a4d8c2SCharles.Forsyth 		}
713*74a4d8c2SCharles.Forsyth 		return len;
714*74a4d8c2SCharles.Forsyth 	}
715*74a4d8c2SCharles.Forsyth 
716*74a4d8c2SCharles.Forsyth 	for(i = 0; i < len; i++){
717*74a4d8c2SCharles.Forsyth 		csr15 = *block++<<16;
718*74a4d8c2SCharles.Forsyth 		csr15 |= *block++<<24;
719*74a4d8c2SCharles.Forsyth 		csr32w(ctlr, 15, csr15);
720*74a4d8c2SCharles.Forsyth 		debug("%8.8uX ", csr15);
721*74a4d8c2SCharles.Forsyth 	}
722*74a4d8c2SCharles.Forsyth 	return 2*len;
723*74a4d8c2SCharles.Forsyth }
724*74a4d8c2SCharles.Forsyth 
725*74a4d8c2SCharles.Forsyth static int
typephylink(Ctlr * ctlr,uchar *)726*74a4d8c2SCharles.Forsyth typephylink(Ctlr* ctlr, uchar*)
727*74a4d8c2SCharles.Forsyth {
728*74a4d8c2SCharles.Forsyth 	int an, bmcr, bmsr, csr6, x;
729*74a4d8c2SCharles.Forsyth 
730*74a4d8c2SCharles.Forsyth 	/*
731*74a4d8c2SCharles.Forsyth 	 * Fail if
732*74a4d8c2SCharles.Forsyth 	 *	auto-negotiataion enabled but not complete;
733*74a4d8c2SCharles.Forsyth 	 *	no valid link established.
734*74a4d8c2SCharles.Forsyth 	 */
735*74a4d8c2SCharles.Forsyth 	bmcr = miir(ctlr, ctlr->curphyad, Bmcr);
736*74a4d8c2SCharles.Forsyth 	miir(ctlr, ctlr->curphyad, Bmsr);
737*74a4d8c2SCharles.Forsyth 	bmsr = miir(ctlr, ctlr->curphyad, Bmsr);
738*74a4d8c2SCharles.Forsyth 	debug("bmcr 0x%2.2uX bmsr 0x%2.2uX\n", bmcr, bmsr);
739*74a4d8c2SCharles.Forsyth 	if(((bmcr & 0x1000) && !(bmsr & 0x0020)) || !(bmsr & 0x0004))
740*74a4d8c2SCharles.Forsyth 		return 0;
741*74a4d8c2SCharles.Forsyth 
742*74a4d8c2SCharles.Forsyth 	if(bmcr & 0x1000){
743*74a4d8c2SCharles.Forsyth 		an = miir(ctlr, ctlr->curphyad, Anar);
744*74a4d8c2SCharles.Forsyth 		an &= miir(ctlr, ctlr->curphyad, Anlpar) & 0x3E0;
745*74a4d8c2SCharles.Forsyth 		debug("an 0x%2.uX 0x%2.2uX 0x%2.2uX\n",
746*74a4d8c2SCharles.Forsyth 	    		miir(ctlr, ctlr->curphyad, Anar),
747*74a4d8c2SCharles.Forsyth 			miir(ctlr, ctlr->curphyad, Anlpar),
748*74a4d8c2SCharles.Forsyth 			an);
749*74a4d8c2SCharles.Forsyth 
750*74a4d8c2SCharles.Forsyth 		if(an & 0x0100)
751*74a4d8c2SCharles.Forsyth 			x = 0x4000;
752*74a4d8c2SCharles.Forsyth 		else if(an & 0x0080)
753*74a4d8c2SCharles.Forsyth 			x = 0x2000;
754*74a4d8c2SCharles.Forsyth 		else if(an & 0x0040)
755*74a4d8c2SCharles.Forsyth 			x = 0x1000;
756*74a4d8c2SCharles.Forsyth 		else if(an & 0x0020)
757*74a4d8c2SCharles.Forsyth 			x = 0x0800;
758*74a4d8c2SCharles.Forsyth 		else
759*74a4d8c2SCharles.Forsyth 			x = 0;
760*74a4d8c2SCharles.Forsyth 	}
761*74a4d8c2SCharles.Forsyth 	else if((bmcr & 0x2100) == 0x2100)
762*74a4d8c2SCharles.Forsyth 		x = 0x4000;
763*74a4d8c2SCharles.Forsyth 	else if(bmcr & 0x2000){
764*74a4d8c2SCharles.Forsyth 		/*
765*74a4d8c2SCharles.Forsyth 		 * If FD capable, force it if necessary.
766*74a4d8c2SCharles.Forsyth 		 */
767*74a4d8c2SCharles.Forsyth 		if((bmsr & 0x4000) && ctlr->fd){
768*74a4d8c2SCharles.Forsyth 			miiw(ctlr, ctlr->curphyad, Bmcr, 0x2100);
769*74a4d8c2SCharles.Forsyth 			x = 0x4000;
770*74a4d8c2SCharles.Forsyth 		}
771*74a4d8c2SCharles.Forsyth 		else
772*74a4d8c2SCharles.Forsyth 			x = 0x2000;
773*74a4d8c2SCharles.Forsyth 	}
774*74a4d8c2SCharles.Forsyth 	else if(bmcr & 0x0100)
775*74a4d8c2SCharles.Forsyth 		x = 0x1000;
776*74a4d8c2SCharles.Forsyth 	else
777*74a4d8c2SCharles.Forsyth 		x = 0x0800;
778*74a4d8c2SCharles.Forsyth 
779*74a4d8c2SCharles.Forsyth 	csr6 = Sc|Mbo|Hbd|Ps|Ca|TrMODE|Sb;
780*74a4d8c2SCharles.Forsyth 	if(ctlr->fdx & x)
781*74a4d8c2SCharles.Forsyth 		csr6 |= Fd;
782*74a4d8c2SCharles.Forsyth 	if(ctlr->ttm & x)
783*74a4d8c2SCharles.Forsyth 		csr6 |= Ttm;
784*74a4d8c2SCharles.Forsyth 	debug("csr6 0x%8.8uX 0x%8.8uX 0x%8.8luX\n",
785*74a4d8c2SCharles.Forsyth 		csr6, ctlr->csr6, csr32r(ctlr, 6));
786*74a4d8c2SCharles.Forsyth 	if(csr6 != ctlr->csr6){
787*74a4d8c2SCharles.Forsyth 		ctlr->csr6 = csr6;
788*74a4d8c2SCharles.Forsyth 		csr32w(ctlr, 6, csr6);
789*74a4d8c2SCharles.Forsyth 	}
790*74a4d8c2SCharles.Forsyth 
791*74a4d8c2SCharles.Forsyth 	return 1;
792*74a4d8c2SCharles.Forsyth }
793*74a4d8c2SCharles.Forsyth 
794*74a4d8c2SCharles.Forsyth static int
typephymode(Ctlr * ctlr,uchar * block,int wait)795*74a4d8c2SCharles.Forsyth typephymode(Ctlr* ctlr, uchar* block, int wait)
796*74a4d8c2SCharles.Forsyth {
797*74a4d8c2SCharles.Forsyth 	uchar *p;
798*74a4d8c2SCharles.Forsyth 	int len, mc, nway, phyx, timeo;
799*74a4d8c2SCharles.Forsyth 
800*74a4d8c2SCharles.Forsyth 	if(DEBUG){
801*74a4d8c2SCharles.Forsyth 		int i;
802*74a4d8c2SCharles.Forsyth 
803*74a4d8c2SCharles.Forsyth 		len = (block[0] & ~0x80)+1;
804*74a4d8c2SCharles.Forsyth 		for(i = 0; i < len; i++)
805*74a4d8c2SCharles.Forsyth 			debug("%2.2uX ", block[i]);
806*74a4d8c2SCharles.Forsyth 		debug("\n");
807*74a4d8c2SCharles.Forsyth 	}
808*74a4d8c2SCharles.Forsyth 
809*74a4d8c2SCharles.Forsyth 	if(block[1] == 1)
810*74a4d8c2SCharles.Forsyth 		len = 1;
811*74a4d8c2SCharles.Forsyth 	else if(block[1] == 3)
812*74a4d8c2SCharles.Forsyth 		len = 2;
813*74a4d8c2SCharles.Forsyth 	else
814*74a4d8c2SCharles.Forsyth 		return -1;
815*74a4d8c2SCharles.Forsyth 
816*74a4d8c2SCharles.Forsyth 	/*
817*74a4d8c2SCharles.Forsyth 	 * Snarf the media capabilities, nway advertisment,
818*74a4d8c2SCharles.Forsyth 	 * FDX and TTM bitmaps.
819*74a4d8c2SCharles.Forsyth 	 */
820*74a4d8c2SCharles.Forsyth 	p = &block[5+len*block[3]+len*block[4+len*block[3]]];
821*74a4d8c2SCharles.Forsyth 	mc = *p++;
822*74a4d8c2SCharles.Forsyth 	mc |= *p++<<8;
823*74a4d8c2SCharles.Forsyth 	nway = *p++;
824*74a4d8c2SCharles.Forsyth 	nway |= *p++<<8;
825*74a4d8c2SCharles.Forsyth 	ctlr->fdx = *p++;
826*74a4d8c2SCharles.Forsyth 	ctlr->fdx |= *p++<<8;
827*74a4d8c2SCharles.Forsyth 	ctlr->ttm = *p++;
828*74a4d8c2SCharles.Forsyth 	ctlr->ttm |= *p<<8;
829*74a4d8c2SCharles.Forsyth 	debug("mc %4.4uX nway %4.4uX fdx %4.4uX ttm %4.4uX\n",
830*74a4d8c2SCharles.Forsyth 		mc, nway, ctlr->fdx, ctlr->ttm);
831*74a4d8c2SCharles.Forsyth 	USED(mc);
832*74a4d8c2SCharles.Forsyth 
833*74a4d8c2SCharles.Forsyth 	phyx = block[2];
834*74a4d8c2SCharles.Forsyth 	ctlr->curphyad = ctlr->phy[phyx];
835*74a4d8c2SCharles.Forsyth 
836*74a4d8c2SCharles.Forsyth 	ctlr->csr6 = 0;//Sc|Mbo|Hbd|Ps|Ca|TrMODE|Sb;
837*74a4d8c2SCharles.Forsyth 	//csr32w(ctlr, 6, ctlr->csr6);
838*74a4d8c2SCharles.Forsyth 	if(typephylink(ctlr, block))
839*74a4d8c2SCharles.Forsyth 		return 0;
840*74a4d8c2SCharles.Forsyth 
841*74a4d8c2SCharles.Forsyth 	if(!(ctlr->phyreset & (1<<phyx))){
842*74a4d8c2SCharles.Forsyth 		debug("reset seq: len %d: ", block[3]);
843*74a4d8c2SCharles.Forsyth 		if(ctlr->type5block)
844*74a4d8c2SCharles.Forsyth 			type5block(ctlr, &ctlr->type5block[2]);
845*74a4d8c2SCharles.Forsyth 		else
846*74a4d8c2SCharles.Forsyth 			type5block(ctlr, &block[4+len*block[3]]);
847*74a4d8c2SCharles.Forsyth 		debug("\n");
848*74a4d8c2SCharles.Forsyth 		ctlr->phyreset |= (1<<phyx);
849*74a4d8c2SCharles.Forsyth 	}
850*74a4d8c2SCharles.Forsyth 
851*74a4d8c2SCharles.Forsyth 	/*
852*74a4d8c2SCharles.Forsyth 	 * GPR sequence.
853*74a4d8c2SCharles.Forsyth 	 */
854*74a4d8c2SCharles.Forsyth 	debug("gpr seq: len %d: ", block[3]);
855*74a4d8c2SCharles.Forsyth 	type5block(ctlr, &block[3]);
856*74a4d8c2SCharles.Forsyth 	debug("\n");
857*74a4d8c2SCharles.Forsyth 
858*74a4d8c2SCharles.Forsyth 	ctlr->csr6 = 0;//Sc|Mbo|Hbd|Ps|Ca|TrMODE|Sb;
859*74a4d8c2SCharles.Forsyth 	//csr32w(ctlr, 6, ctlr->csr6);
860*74a4d8c2SCharles.Forsyth 	if(typephylink(ctlr, block))
861*74a4d8c2SCharles.Forsyth 		return 0;
862*74a4d8c2SCharles.Forsyth 
863*74a4d8c2SCharles.Forsyth 	/*
864*74a4d8c2SCharles.Forsyth 	 * Turn off auto-negotiation, set the auto-negotiation
865*74a4d8c2SCharles.Forsyth 	 * advertisment register then start the auto-negotiation
866*74a4d8c2SCharles.Forsyth 	 * process again.
867*74a4d8c2SCharles.Forsyth 	 */
868*74a4d8c2SCharles.Forsyth 	miiw(ctlr, ctlr->curphyad, Bmcr, 0);
869*74a4d8c2SCharles.Forsyth 	miiw(ctlr, ctlr->curphyad, Anar, nway|1);
870*74a4d8c2SCharles.Forsyth 	miiw(ctlr, ctlr->curphyad, Bmcr, 0x1000);
871*74a4d8c2SCharles.Forsyth 
872*74a4d8c2SCharles.Forsyth 	if(!wait)
873*74a4d8c2SCharles.Forsyth 		return 0;
874*74a4d8c2SCharles.Forsyth 
875*74a4d8c2SCharles.Forsyth 	for(timeo = 0; timeo < 30; timeo++){
876*74a4d8c2SCharles.Forsyth 		if(typephylink(ctlr, block))
877*74a4d8c2SCharles.Forsyth 			return 0;
878*74a4d8c2SCharles.Forsyth 		delay(100);
879*74a4d8c2SCharles.Forsyth 	}
880*74a4d8c2SCharles.Forsyth 
881*74a4d8c2SCharles.Forsyth 	return -1;
882*74a4d8c2SCharles.Forsyth }
883*74a4d8c2SCharles.Forsyth 
884*74a4d8c2SCharles.Forsyth static int
typesymmode(Ctlr * ctlr,uchar * block,int wait)885*74a4d8c2SCharles.Forsyth typesymmode(Ctlr *ctlr, uchar *block, int wait)
886*74a4d8c2SCharles.Forsyth {
887*74a4d8c2SCharles.Forsyth 	uint gpmode, gpdata, command;
888*74a4d8c2SCharles.Forsyth 
889*74a4d8c2SCharles.Forsyth 	USED(wait);
890*74a4d8c2SCharles.Forsyth 	gpmode = block[3] | ((uint) block[4] << 8);
891*74a4d8c2SCharles.Forsyth 	gpdata = block[5] | ((uint) block[6] << 8);
892*74a4d8c2SCharles.Forsyth 	command = (block[7] | ((uint) block[8] << 8)) & 0x71;
893*74a4d8c2SCharles.Forsyth 	if (command & 0x8000) {
894*74a4d8c2SCharles.Forsyth 		print("ether2114x.c: FIXME: handle type 4 mode blocks where cmd.active_invalid != 0\n");
895*74a4d8c2SCharles.Forsyth 		return -1;
896*74a4d8c2SCharles.Forsyth 	}
897*74a4d8c2SCharles.Forsyth 	csr32w(ctlr, 15, gpmode);
898*74a4d8c2SCharles.Forsyth 	csr32w(ctlr, 15, gpdata);
899*74a4d8c2SCharles.Forsyth 	ctlr->csr6 = (command & 0x71) << 18;
900*74a4d8c2SCharles.Forsyth 	csr32w(ctlr, 6, ctlr->csr6);
901*74a4d8c2SCharles.Forsyth 	return 0;
902*74a4d8c2SCharles.Forsyth }
903*74a4d8c2SCharles.Forsyth 
904*74a4d8c2SCharles.Forsyth static int
type2mode(Ctlr * ctlr,uchar * block,int)905*74a4d8c2SCharles.Forsyth type2mode(Ctlr* ctlr, uchar* block, int)
906*74a4d8c2SCharles.Forsyth {
907*74a4d8c2SCharles.Forsyth 	uchar *p;
908*74a4d8c2SCharles.Forsyth 	int csr6, csr13, csr14, csr15, gpc, gpd;
909*74a4d8c2SCharles.Forsyth 
910*74a4d8c2SCharles.Forsyth 	csr6 = Sc|Mbo|Ca|TrMODE|Sb;
911*74a4d8c2SCharles.Forsyth 	debug("type2mode: medium 0x%2.2uX\n", block[2]);
912*74a4d8c2SCharles.Forsyth 
913*74a4d8c2SCharles.Forsyth 	/*
914*74a4d8c2SCharles.Forsyth 	 * Don't attempt full-duplex
915*74a4d8c2SCharles.Forsyth 	 * unless explicitly requested.
916*74a4d8c2SCharles.Forsyth 	 */
917*74a4d8c2SCharles.Forsyth 	if((block[2] & 0x3F) == 0x04){	/* 10BASE-TFD */
918*74a4d8c2SCharles.Forsyth 		if(!ctlr->fd)
919*74a4d8c2SCharles.Forsyth 			return -1;
920*74a4d8c2SCharles.Forsyth 		csr6 |= Fd;
921*74a4d8c2SCharles.Forsyth 	}
922*74a4d8c2SCharles.Forsyth 
923*74a4d8c2SCharles.Forsyth 	/*
924*74a4d8c2SCharles.Forsyth 	 * Operating mode programming values from the datasheet
925*74a4d8c2SCharles.Forsyth 	 * unless media specific data is explicitly given.
926*74a4d8c2SCharles.Forsyth 	 */
927*74a4d8c2SCharles.Forsyth 	p = &block[3];
928*74a4d8c2SCharles.Forsyth 	if(block[2] & 0x40){
929*74a4d8c2SCharles.Forsyth 		csr13 = (block[4]<<8)|block[3];
930*74a4d8c2SCharles.Forsyth 		csr14 = (block[6]<<8)|block[5];
931*74a4d8c2SCharles.Forsyth 		csr15 = (block[8]<<8)|block[7];
932*74a4d8c2SCharles.Forsyth 		p += 6;
933*74a4d8c2SCharles.Forsyth 	}
934*74a4d8c2SCharles.Forsyth 	else switch(block[2] & 0x3F){
935*74a4d8c2SCharles.Forsyth 	default:
936*74a4d8c2SCharles.Forsyth 		return -1;
937*74a4d8c2SCharles.Forsyth 	case 0x00:			/* 10BASE-T */
938*74a4d8c2SCharles.Forsyth 		csr13 = 0x00000001;
939*74a4d8c2SCharles.Forsyth 		csr14 = 0x00007F3F;
940*74a4d8c2SCharles.Forsyth 		csr15 = 0x00000008;
941*74a4d8c2SCharles.Forsyth 		break;
942*74a4d8c2SCharles.Forsyth 	case 0x01:			/* 10BASE-2 */
943*74a4d8c2SCharles.Forsyth 		csr13 = 0x00000009;
944*74a4d8c2SCharles.Forsyth 		csr14 = 0x00000705;
945*74a4d8c2SCharles.Forsyth 		csr15 = 0x00000006;
946*74a4d8c2SCharles.Forsyth 		break;
947*74a4d8c2SCharles.Forsyth 	case 0x02:			/* 10BASE-5 (AUI) */
948*74a4d8c2SCharles.Forsyth 		csr13 = 0x00000009;
949*74a4d8c2SCharles.Forsyth 		csr14 = 0x00000705;
950*74a4d8c2SCharles.Forsyth 		csr15 = 0x0000000E;
951*74a4d8c2SCharles.Forsyth 		break;
952*74a4d8c2SCharles.Forsyth 	case 0x04:			/* 10BASE-TFD */
953*74a4d8c2SCharles.Forsyth 		csr13 = 0x00000001;
954*74a4d8c2SCharles.Forsyth 		csr14 = 0x00007F3D;
955*74a4d8c2SCharles.Forsyth 		csr15 = 0x00000008;
956*74a4d8c2SCharles.Forsyth 		break;
957*74a4d8c2SCharles.Forsyth 	}
958*74a4d8c2SCharles.Forsyth 	gpc = *p++<<16;
959*74a4d8c2SCharles.Forsyth 	gpc |= *p++<<24;
960*74a4d8c2SCharles.Forsyth 	gpd = *p++<<16;
961*74a4d8c2SCharles.Forsyth 	gpd |= *p<<24;
962*74a4d8c2SCharles.Forsyth 
963*74a4d8c2SCharles.Forsyth 	csr32w(ctlr, 13, 0);
964*74a4d8c2SCharles.Forsyth 	csr32w(ctlr, 14, csr14);
965*74a4d8c2SCharles.Forsyth 	csr32w(ctlr, 15, gpc|csr15);
966*74a4d8c2SCharles.Forsyth 	delay(10);
967*74a4d8c2SCharles.Forsyth 	csr32w(ctlr, 15, gpd|csr15);
968*74a4d8c2SCharles.Forsyth 	csr32w(ctlr, 13, csr13);
969*74a4d8c2SCharles.Forsyth 
970*74a4d8c2SCharles.Forsyth 	ctlr->csr6 = csr6;
971*74a4d8c2SCharles.Forsyth 	csr32w(ctlr, 6, ctlr->csr6);
972*74a4d8c2SCharles.Forsyth 
973*74a4d8c2SCharles.Forsyth 	debug("type2mode: csr13 %8.8uX csr14 %8.8uX csr15 %8.8uX\n",
974*74a4d8c2SCharles.Forsyth 		csr13, csr14, csr15);
975*74a4d8c2SCharles.Forsyth 	debug("type2mode: gpc %8.8uX gpd %8.8uX csr6 %8.8uX\n",
976*74a4d8c2SCharles.Forsyth 		gpc, gpd, csr6);
977*74a4d8c2SCharles.Forsyth 
978*74a4d8c2SCharles.Forsyth 	return 0;
979*74a4d8c2SCharles.Forsyth }
980*74a4d8c2SCharles.Forsyth 
981*74a4d8c2SCharles.Forsyth static int
type0link(Ctlr * ctlr,uchar * block)982*74a4d8c2SCharles.Forsyth type0link(Ctlr* ctlr, uchar* block)
983*74a4d8c2SCharles.Forsyth {
984*74a4d8c2SCharles.Forsyth 	int m, polarity, sense;
985*74a4d8c2SCharles.Forsyth 
986*74a4d8c2SCharles.Forsyth 	m = (block[3]<<8)|block[2];
987*74a4d8c2SCharles.Forsyth 	sense = 1<<((m & 0x000E)>>1);
988*74a4d8c2SCharles.Forsyth 	if(m & 0x0080)
989*74a4d8c2SCharles.Forsyth 		polarity = sense;
990*74a4d8c2SCharles.Forsyth 	else
991*74a4d8c2SCharles.Forsyth 		polarity = 0;
992*74a4d8c2SCharles.Forsyth 
993*74a4d8c2SCharles.Forsyth 	return (csr32r(ctlr, 12) & sense)^polarity;
994*74a4d8c2SCharles.Forsyth }
995*74a4d8c2SCharles.Forsyth 
996*74a4d8c2SCharles.Forsyth static int
type0mode(Ctlr * ctlr,uchar * block,int wait)997*74a4d8c2SCharles.Forsyth type0mode(Ctlr* ctlr, uchar* block, int wait)
998*74a4d8c2SCharles.Forsyth {
999*74a4d8c2SCharles.Forsyth 	int csr6, m, timeo;
1000*74a4d8c2SCharles.Forsyth 
1001*74a4d8c2SCharles.Forsyth 	csr6 = Sc|Mbo|Hbd|Ca|TrMODE|Sb;
1002*74a4d8c2SCharles.Forsyth debug("type0: medium 0x%uX, fd %d: 0x%2.2uX 0x%2.2uX 0x%2.2uX 0x%2.2uX\n",
1003*74a4d8c2SCharles.Forsyth     ctlr->medium, ctlr->fd, block[0], block[1], block[2], block[3]);
1004*74a4d8c2SCharles.Forsyth 	switch(block[0]){
1005*74a4d8c2SCharles.Forsyth 	default:
1006*74a4d8c2SCharles.Forsyth 		break;
1007*74a4d8c2SCharles.Forsyth 
1008*74a4d8c2SCharles.Forsyth 	case 0x04:			/* 10BASE-TFD */
1009*74a4d8c2SCharles.Forsyth 	case 0x05:			/* 100BASE-TXFD */
1010*74a4d8c2SCharles.Forsyth 	case 0x08:			/* 100BASE-FXFD */
1011*74a4d8c2SCharles.Forsyth 		/*
1012*74a4d8c2SCharles.Forsyth 		 * Don't attempt full-duplex
1013*74a4d8c2SCharles.Forsyth 		 * unless explicitly requested.
1014*74a4d8c2SCharles.Forsyth 		 */
1015*74a4d8c2SCharles.Forsyth 		if(!ctlr->fd)
1016*74a4d8c2SCharles.Forsyth 			return -1;
1017*74a4d8c2SCharles.Forsyth 		csr6 |= Fd;
1018*74a4d8c2SCharles.Forsyth 		break;
1019*74a4d8c2SCharles.Forsyth 	}
1020*74a4d8c2SCharles.Forsyth 
1021*74a4d8c2SCharles.Forsyth 	m = (block[3]<<8)|block[2];
1022*74a4d8c2SCharles.Forsyth 	if(m & 0x0001)
1023*74a4d8c2SCharles.Forsyth 		csr6 |= Ps;
1024*74a4d8c2SCharles.Forsyth 	if(m & 0x0010)
1025*74a4d8c2SCharles.Forsyth 		csr6 |= Ttm;
1026*74a4d8c2SCharles.Forsyth 	if(m & 0x0020)
1027*74a4d8c2SCharles.Forsyth 		csr6 |= Pcs;
1028*74a4d8c2SCharles.Forsyth 	if(m & 0x0040)
1029*74a4d8c2SCharles.Forsyth 		csr6 |= Scr;
1030*74a4d8c2SCharles.Forsyth 
1031*74a4d8c2SCharles.Forsyth 	csr32w(ctlr, 12, block[1]);
1032*74a4d8c2SCharles.Forsyth 	microdelay(10);
1033*74a4d8c2SCharles.Forsyth 	csr32w(ctlr, 6, csr6);
1034*74a4d8c2SCharles.Forsyth 	ctlr->csr6 = csr6;
1035*74a4d8c2SCharles.Forsyth 
1036*74a4d8c2SCharles.Forsyth 	if(!wait)
1037*74a4d8c2SCharles.Forsyth 		return 0;
1038*74a4d8c2SCharles.Forsyth 
1039*74a4d8c2SCharles.Forsyth 	for(timeo = 0; timeo < 30; timeo++){
1040*74a4d8c2SCharles.Forsyth 		if(type0link(ctlr, block))
1041*74a4d8c2SCharles.Forsyth 			return 0;
1042*74a4d8c2SCharles.Forsyth 		delay(100);
1043*74a4d8c2SCharles.Forsyth 	}
1044*74a4d8c2SCharles.Forsyth 
1045*74a4d8c2SCharles.Forsyth 	return -1;
1046*74a4d8c2SCharles.Forsyth }
1047*74a4d8c2SCharles.Forsyth 
1048*74a4d8c2SCharles.Forsyth static int
media21041(Ether * ether,int wait)1049*74a4d8c2SCharles.Forsyth media21041(Ether* ether, int wait)
1050*74a4d8c2SCharles.Forsyth {
1051*74a4d8c2SCharles.Forsyth 	Ctlr* ctlr;
1052*74a4d8c2SCharles.Forsyth 	uchar *block;
1053*74a4d8c2SCharles.Forsyth 	int csr6, csr13, csr14, csr15, medium, timeo;
1054*74a4d8c2SCharles.Forsyth 
1055*74a4d8c2SCharles.Forsyth 	ctlr = ether->ctlr;
1056*74a4d8c2SCharles.Forsyth 	block = ctlr->infoblock[ctlr->curk];
1057*74a4d8c2SCharles.Forsyth 	debug("media21041: block[0] %2.2uX, medium %4.4uX sct %4.4uX\n",
1058*74a4d8c2SCharles.Forsyth 		block[0], ctlr->medium, ctlr->sct);
1059*74a4d8c2SCharles.Forsyth 
1060*74a4d8c2SCharles.Forsyth 	medium = block[0] & 0x3F;
1061*74a4d8c2SCharles.Forsyth 	if(ctlr->medium >= 0 && medium != ctlr->medium)
1062*74a4d8c2SCharles.Forsyth 		return 0;
1063*74a4d8c2SCharles.Forsyth 	if(ctlr->sct != 0x0800 && (ctlr->sct & 0x3F) != medium)
1064*74a4d8c2SCharles.Forsyth 		return 0;
1065*74a4d8c2SCharles.Forsyth 
1066*74a4d8c2SCharles.Forsyth 	csr6 = Sc|Mbo|Ca|TrMODE|Sb;
1067*74a4d8c2SCharles.Forsyth 	if(block[0] & 0x40){
1068*74a4d8c2SCharles.Forsyth 		csr13 = (block[2]<<8)|block[1];
1069*74a4d8c2SCharles.Forsyth 		csr14 = (block[4]<<8)|block[3];
1070*74a4d8c2SCharles.Forsyth 		csr15 = (block[6]<<8)|block[5];
1071*74a4d8c2SCharles.Forsyth 	}
1072*74a4d8c2SCharles.Forsyth 	else switch(medium){
1073*74a4d8c2SCharles.Forsyth 	default:
1074*74a4d8c2SCharles.Forsyth 		return -1;
1075*74a4d8c2SCharles.Forsyth 	case 0x00:		/* 10BASE-T */
1076*74a4d8c2SCharles.Forsyth 		csr13 = 0xEF01;
1077*74a4d8c2SCharles.Forsyth 		csr14 = 0xFF3F;
1078*74a4d8c2SCharles.Forsyth 		csr15 = 0x0008;
1079*74a4d8c2SCharles.Forsyth 		break;
1080*74a4d8c2SCharles.Forsyth 	case 0x01:		/* 10BASE-2 */
1081*74a4d8c2SCharles.Forsyth 		csr13 = 0xEF09;
1082*74a4d8c2SCharles.Forsyth 		csr14 = 0xF73D;
1083*74a4d8c2SCharles.Forsyth 		csr15 = 0x0006;
1084*74a4d8c2SCharles.Forsyth 		break;
1085*74a4d8c2SCharles.Forsyth 	case 0x02:		/* 10BASE-5 */
1086*74a4d8c2SCharles.Forsyth 		csr13 = 0xEF09;
1087*74a4d8c2SCharles.Forsyth 		csr14 = 0xF73D;
1088*74a4d8c2SCharles.Forsyth 		csr15 = 0x000E;
1089*74a4d8c2SCharles.Forsyth 		break;
1090*74a4d8c2SCharles.Forsyth 	case 0x04:		/* 10BASE-TFD */
1091*74a4d8c2SCharles.Forsyth 		csr13 = 0xEF01;
1092*74a4d8c2SCharles.Forsyth 		csr14 = 0xFF3D;
1093*74a4d8c2SCharles.Forsyth 		csr15 = 0x0008;
1094*74a4d8c2SCharles.Forsyth 		break;
1095*74a4d8c2SCharles.Forsyth 	}
1096*74a4d8c2SCharles.Forsyth 
1097*74a4d8c2SCharles.Forsyth 	csr32w(ctlr, 13, 0);
1098*74a4d8c2SCharles.Forsyth 	csr32w(ctlr, 14, csr14);
1099*74a4d8c2SCharles.Forsyth 	csr32w(ctlr, 15, csr15);
1100*74a4d8c2SCharles.Forsyth 	csr32w(ctlr, 13, csr13);
1101*74a4d8c2SCharles.Forsyth 	delay(10);
1102*74a4d8c2SCharles.Forsyth 
1103*74a4d8c2SCharles.Forsyth 	if(medium == 0x04)
1104*74a4d8c2SCharles.Forsyth 		csr6 |= Fd;
1105*74a4d8c2SCharles.Forsyth 	ctlr->csr6 = csr6;
1106*74a4d8c2SCharles.Forsyth 	csr32w(ctlr, 6, ctlr->csr6);
1107*74a4d8c2SCharles.Forsyth 
1108*74a4d8c2SCharles.Forsyth 	debug("media21041: csr6 %8.8uX csr13 %4.4uX csr14 %4.4uX csr15 %4.4uX\n",
1109*74a4d8c2SCharles.Forsyth 		csr6, csr13, csr14, csr15);
1110*74a4d8c2SCharles.Forsyth 
1111*74a4d8c2SCharles.Forsyth 	if(!wait)
1112*74a4d8c2SCharles.Forsyth 		return 0;
1113*74a4d8c2SCharles.Forsyth 
1114*74a4d8c2SCharles.Forsyth 	for(timeo = 0; timeo < 30; timeo++){
1115*74a4d8c2SCharles.Forsyth 		if(!(csr32r(ctlr, 12) & 0x0002)){
1116*74a4d8c2SCharles.Forsyth 			debug("media21041: ok: csr12 %4.4luX timeo %d\n",
1117*74a4d8c2SCharles.Forsyth 				csr32r(ctlr, 12), timeo);
1118*74a4d8c2SCharles.Forsyth 			return 10;
1119*74a4d8c2SCharles.Forsyth 		}
1120*74a4d8c2SCharles.Forsyth 		delay(100);
1121*74a4d8c2SCharles.Forsyth 	}
1122*74a4d8c2SCharles.Forsyth 	debug("media21041: !ok: csr12 %4.4luX\n", csr32r(ctlr, 12));
1123*74a4d8c2SCharles.Forsyth 
1124*74a4d8c2SCharles.Forsyth 	return -1;
1125*74a4d8c2SCharles.Forsyth }
1126*74a4d8c2SCharles.Forsyth 
1127*74a4d8c2SCharles.Forsyth static int
mediaxx(Ether * ether,int wait)1128*74a4d8c2SCharles.Forsyth mediaxx(Ether* ether, int wait)
1129*74a4d8c2SCharles.Forsyth {
1130*74a4d8c2SCharles.Forsyth 	Ctlr* ctlr;
1131*74a4d8c2SCharles.Forsyth 	uchar *block;
1132*74a4d8c2SCharles.Forsyth 
1133*74a4d8c2SCharles.Forsyth 	ctlr = ether->ctlr;
1134*74a4d8c2SCharles.Forsyth 	block = ctlr->infoblock[ctlr->curk];
1135*74a4d8c2SCharles.Forsyth 	if(block[0] & 0x80){
1136*74a4d8c2SCharles.Forsyth 		switch(block[1]){
1137*74a4d8c2SCharles.Forsyth 		default:
1138*74a4d8c2SCharles.Forsyth 			return -1;
1139*74a4d8c2SCharles.Forsyth 		case 0:
1140*74a4d8c2SCharles.Forsyth 			if(ctlr->medium >= 0 && block[2] != ctlr->medium)
1141*74a4d8c2SCharles.Forsyth 				return 0;
1142*74a4d8c2SCharles.Forsyth /* need this test? */	if(ctlr->sct != 0x0800 && (ctlr->sct & 0x3F) != block[2])
1143*74a4d8c2SCharles.Forsyth 				return 0;
1144*74a4d8c2SCharles.Forsyth 			if(type0mode(ctlr, block+2, wait))
1145*74a4d8c2SCharles.Forsyth 				return 0;
1146*74a4d8c2SCharles.Forsyth 			break;
1147*74a4d8c2SCharles.Forsyth 		case 1:
1148*74a4d8c2SCharles.Forsyth 			if(typephymode(ctlr, block, wait))
1149*74a4d8c2SCharles.Forsyth 				return 0;
1150*74a4d8c2SCharles.Forsyth 			break;
1151*74a4d8c2SCharles.Forsyth 		case 2:
1152*74a4d8c2SCharles.Forsyth 			debug("type2: medium %d block[2] %d\n",
1153*74a4d8c2SCharles.Forsyth 				ctlr->medium, block[2]);
1154*74a4d8c2SCharles.Forsyth 			if(ctlr->medium >= 0 && ((block[2] & 0x3F) != ctlr->medium))
1155*74a4d8c2SCharles.Forsyth 				return 0;
1156*74a4d8c2SCharles.Forsyth 			if(type2mode(ctlr, block, wait))
1157*74a4d8c2SCharles.Forsyth 				return 0;
1158*74a4d8c2SCharles.Forsyth 			break;
1159*74a4d8c2SCharles.Forsyth 		case 3:
1160*74a4d8c2SCharles.Forsyth 			if(typephymode(ctlr, block, wait))
1161*74a4d8c2SCharles.Forsyth 				return 0;
1162*74a4d8c2SCharles.Forsyth 			break;
1163*74a4d8c2SCharles.Forsyth 		case 4:
1164*74a4d8c2SCharles.Forsyth 			debug("type4: medium %d block[2] %d\n",
1165*74a4d8c2SCharles.Forsyth 				ctlr->medium, block[2]);
1166*74a4d8c2SCharles.Forsyth 			if(ctlr->medium >= 0 && ((block[2] & 0x3F) != ctlr->medium))
1167*74a4d8c2SCharles.Forsyth 				return 0;
1168*74a4d8c2SCharles.Forsyth 			if(typesymmode(ctlr, block, wait))
1169*74a4d8c2SCharles.Forsyth 				return 0;
1170*74a4d8c2SCharles.Forsyth 			break;
1171*74a4d8c2SCharles.Forsyth 		}
1172*74a4d8c2SCharles.Forsyth 	}
1173*74a4d8c2SCharles.Forsyth 	else{
1174*74a4d8c2SCharles.Forsyth 		if(ctlr->medium >= 0 && block[0] != ctlr->medium)
1175*74a4d8c2SCharles.Forsyth 			return 0;
1176*74a4d8c2SCharles.Forsyth /* need this test? */if(ctlr->sct != 0x0800 && (ctlr->sct & 0x3F) != block[0])
1177*74a4d8c2SCharles.Forsyth 			return 0;
1178*74a4d8c2SCharles.Forsyth 		if(type0mode(ctlr, block, wait))
1179*74a4d8c2SCharles.Forsyth 			return 0;
1180*74a4d8c2SCharles.Forsyth 	}
1181*74a4d8c2SCharles.Forsyth 
1182*74a4d8c2SCharles.Forsyth 	if(ctlr->csr6){
1183*74a4d8c2SCharles.Forsyth 		if(!(ctlr->csr6 & Ps) || (ctlr->csr6 & Ttm))
1184*74a4d8c2SCharles.Forsyth 			return 10;
1185*74a4d8c2SCharles.Forsyth 		return 100;
1186*74a4d8c2SCharles.Forsyth 	}
1187*74a4d8c2SCharles.Forsyth 
1188*74a4d8c2SCharles.Forsyth 	return 0;
1189*74a4d8c2SCharles.Forsyth }
1190*74a4d8c2SCharles.Forsyth 
1191*74a4d8c2SCharles.Forsyth static int
media(Ether * ether,int wait)1192*74a4d8c2SCharles.Forsyth media(Ether* ether, int wait)
1193*74a4d8c2SCharles.Forsyth {
1194*74a4d8c2SCharles.Forsyth 	Ctlr* ctlr;
1195*74a4d8c2SCharles.Forsyth 	int k, mbps;
1196*74a4d8c2SCharles.Forsyth 
1197*74a4d8c2SCharles.Forsyth 	ctlr = ether->ctlr;
1198*74a4d8c2SCharles.Forsyth 	for(k = 0; k < ctlr->k; k++){
1199*74a4d8c2SCharles.Forsyth 		switch(ctlr->id){
1200*74a4d8c2SCharles.Forsyth 		default:
1201*74a4d8c2SCharles.Forsyth 			mbps = mediaxx(ether, wait);
1202*74a4d8c2SCharles.Forsyth 			break;
1203*74a4d8c2SCharles.Forsyth 		case Tulip1:			/* 21041 */
1204*74a4d8c2SCharles.Forsyth 			mbps = media21041(ether, wait);
1205*74a4d8c2SCharles.Forsyth 			break;
1206*74a4d8c2SCharles.Forsyth 		}
1207*74a4d8c2SCharles.Forsyth 		if(mbps > 0)
1208*74a4d8c2SCharles.Forsyth 			return mbps;
1209*74a4d8c2SCharles.Forsyth 		if(ctlr->curk == 0)
1210*74a4d8c2SCharles.Forsyth 			ctlr->curk = ctlr->k-1;
1211*74a4d8c2SCharles.Forsyth 		else
1212*74a4d8c2SCharles.Forsyth 			ctlr->curk--;
1213*74a4d8c2SCharles.Forsyth 	}
1214*74a4d8c2SCharles.Forsyth 
1215*74a4d8c2SCharles.Forsyth 	return 0;
1216*74a4d8c2SCharles.Forsyth }
1217*74a4d8c2SCharles.Forsyth 
1218*74a4d8c2SCharles.Forsyth static char* mediatable[9] = {
1219*74a4d8c2SCharles.Forsyth 	"10BASE-T",			/* TP */
1220*74a4d8c2SCharles.Forsyth 	"10BASE-2",			/* BNC */
1221*74a4d8c2SCharles.Forsyth 	"10BASE-5",			/* AUI */
1222*74a4d8c2SCharles.Forsyth 	"100BASE-TX",
1223*74a4d8c2SCharles.Forsyth 	"10BASE-TFD",
1224*74a4d8c2SCharles.Forsyth 	"100BASE-TXFD",
1225*74a4d8c2SCharles.Forsyth 	"100BASE-T4",
1226*74a4d8c2SCharles.Forsyth 	"100BASE-FX",
1227*74a4d8c2SCharles.Forsyth 	"100BASE-FXFD",
1228*74a4d8c2SCharles.Forsyth };
1229*74a4d8c2SCharles.Forsyth 
1230*74a4d8c2SCharles.Forsyth static uchar en1207[] = {		/* Accton EN1207-COMBO */
1231*74a4d8c2SCharles.Forsyth 	0x00, 0x00, 0xE8,		/* [0]  vendor ethernet code */
1232*74a4d8c2SCharles.Forsyth 	0x00,				/* [3]  spare */
1233*74a4d8c2SCharles.Forsyth 
1234*74a4d8c2SCharles.Forsyth 	0x00, 0x08,			/* [4]  connection (LSB+MSB = 0x0800) */
1235*74a4d8c2SCharles.Forsyth 	0x1F,				/* [6]  general purpose control */
1236*74a4d8c2SCharles.Forsyth 	2,				/* [7]  block count */
1237*74a4d8c2SCharles.Forsyth 
1238*74a4d8c2SCharles.Forsyth 	0x00,				/* [8]  media code (10BASE-TX) */
1239*74a4d8c2SCharles.Forsyth 	0x0B,				/* [9]  general purpose port data */
1240*74a4d8c2SCharles.Forsyth 	0x9E, 0x00,			/* [10] command (LSB+MSB = 0x009E) */
1241*74a4d8c2SCharles.Forsyth 
1242*74a4d8c2SCharles.Forsyth 	0x03,				/* [8]  media code (100BASE-TX) */
1243*74a4d8c2SCharles.Forsyth 	0x1B,				/* [9]  general purpose port data */
1244*74a4d8c2SCharles.Forsyth 	0x6D, 0x00,			/* [10] command (LSB+MSB = 0x006D) */
1245*74a4d8c2SCharles.Forsyth 
1246*74a4d8c2SCharles.Forsyth 					/* There is 10BASE-2 as well, but... */
1247*74a4d8c2SCharles.Forsyth };
1248*74a4d8c2SCharles.Forsyth 
1249*74a4d8c2SCharles.Forsyth static uchar ana6910fx[] = {		/* Adaptec (Cogent) ANA-6910FX */
1250*74a4d8c2SCharles.Forsyth 	0x00, 0x00, 0x92,		/* [0]  vendor ethernet code */
1251*74a4d8c2SCharles.Forsyth 	0x00,				/* [3]  spare */
1252*74a4d8c2SCharles.Forsyth 
1253*74a4d8c2SCharles.Forsyth 	0x00, 0x08,			/* [4]  connection (LSB+MSB = 0x0800) */
1254*74a4d8c2SCharles.Forsyth 	0x3F,				/* [6]  general purpose control */
1255*74a4d8c2SCharles.Forsyth 	1,				/* [7]  block count */
1256*74a4d8c2SCharles.Forsyth 
1257*74a4d8c2SCharles.Forsyth 	0x07,				/* [8]  media code (100BASE-FX) */
1258*74a4d8c2SCharles.Forsyth 	0x03,				/* [9]  general purpose port data */
1259*74a4d8c2SCharles.Forsyth 	0x2D, 0x00			/* [10] command (LSB+MSB = 0x000D) */
1260*74a4d8c2SCharles.Forsyth };
1261*74a4d8c2SCharles.Forsyth 
1262*74a4d8c2SCharles.Forsyth static uchar smc9332[] = {		/* SMC 9332 */
1263*74a4d8c2SCharles.Forsyth 	0x00, 0x00, 0xC0,		/* [0]  vendor ethernet code */
1264*74a4d8c2SCharles.Forsyth 	0x00,				/* [3]  spare */
1265*74a4d8c2SCharles.Forsyth 
1266*74a4d8c2SCharles.Forsyth 	0x00, 0x08,			/* [4]  connection (LSB+MSB = 0x0800) */
1267*74a4d8c2SCharles.Forsyth 	0x1F,				/* [6]  general purpose control */
1268*74a4d8c2SCharles.Forsyth 	2,				/* [7]  block count */
1269*74a4d8c2SCharles.Forsyth 
1270*74a4d8c2SCharles.Forsyth 	0x00,				/* [8]  media code (10BASE-TX) */
1271*74a4d8c2SCharles.Forsyth 	0x00,				/* [9]  general purpose port data */
1272*74a4d8c2SCharles.Forsyth 	0x9E, 0x00,			/* [10] command (LSB+MSB = 0x009E) */
1273*74a4d8c2SCharles.Forsyth 
1274*74a4d8c2SCharles.Forsyth 	0x03,				/* [8]  media code (100BASE-TX) */
1275*74a4d8c2SCharles.Forsyth 	0x09,				/* [9]  general purpose port data */
1276*74a4d8c2SCharles.Forsyth 	0x6D, 0x00,			/* [10] command (LSB+MSB = 0x006D) */
1277*74a4d8c2SCharles.Forsyth };
1278*74a4d8c2SCharles.Forsyth 
1279*74a4d8c2SCharles.Forsyth static uchar* leaf21140[] = {
1280*74a4d8c2SCharles.Forsyth 	en1207,				/* Accton EN1207-COMBO */
1281*74a4d8c2SCharles.Forsyth 	ana6910fx,			/* Adaptec (Cogent) ANA-6910FX */
1282*74a4d8c2SCharles.Forsyth 	smc9332,			/* SMC 9332 */
1283*74a4d8c2SCharles.Forsyth 	0,
1284*74a4d8c2SCharles.Forsyth };
1285*74a4d8c2SCharles.Forsyth 
1286*74a4d8c2SCharles.Forsyth /*
1287*74a4d8c2SCharles.Forsyth  * Copied to ctlr->srom at offset 20.
1288*74a4d8c2SCharles.Forsyth  */
1289*74a4d8c2SCharles.Forsyth static uchar leafpnic[] = {
1290*74a4d8c2SCharles.Forsyth 	0x00, 0x00, 0x00, 0x00,		/* MAC address */
1291*74a4d8c2SCharles.Forsyth 	0x00, 0x00,
1292*74a4d8c2SCharles.Forsyth 	0x00,				/* controller 0 device number */
1293*74a4d8c2SCharles.Forsyth 	0x1E, 0x00,			/* controller 0 info leaf offset */
1294*74a4d8c2SCharles.Forsyth 	0x00,				/* reserved */
1295*74a4d8c2SCharles.Forsyth 	0x00, 0x08,			/* selected connection type */
1296*74a4d8c2SCharles.Forsyth 	0x00,				/* general purpose control */
1297*74a4d8c2SCharles.Forsyth 	0x01,				/* block count */
1298*74a4d8c2SCharles.Forsyth 
1299*74a4d8c2SCharles.Forsyth 	0x8C,				/* format indicator and count */
1300*74a4d8c2SCharles.Forsyth 	0x01,				/* block type */
1301*74a4d8c2SCharles.Forsyth 	0x00,				/* PHY number */
1302*74a4d8c2SCharles.Forsyth 	0x00,				/* GPR sequence length */
1303*74a4d8c2SCharles.Forsyth 	0x00,				/* reset sequence length */
1304*74a4d8c2SCharles.Forsyth 	0x00, 0x78,			/* media capabilities */
1305*74a4d8c2SCharles.Forsyth 	0xE0, 0x01,			/* Nway advertisment */
1306*74a4d8c2SCharles.Forsyth 	0x00, 0x50,			/* FDX bitmap */
1307*74a4d8c2SCharles.Forsyth 	0x00, 0x18,			/* TTM bitmap */
1308*74a4d8c2SCharles.Forsyth };
1309*74a4d8c2SCharles.Forsyth 
1310*74a4d8c2SCharles.Forsyth static int
srom(Ctlr * ctlr)1311*74a4d8c2SCharles.Forsyth srom(Ctlr* ctlr)
1312*74a4d8c2SCharles.Forsyth {
1313*74a4d8c2SCharles.Forsyth 	int i, k, oui, phy, x;
1314*74a4d8c2SCharles.Forsyth 	uchar *p;
1315*74a4d8c2SCharles.Forsyth 
1316*74a4d8c2SCharles.Forsyth 	/*
1317*74a4d8c2SCharles.Forsyth 	 * This is a partial decoding of the SROM format described in
1318*74a4d8c2SCharles.Forsyth 	 * 'Digital Semiconductor 21X4 Serial ROM Format, Version 4.05,
1319*74a4d8c2SCharles.Forsyth 	 * 2-Mar-98'. Only the 2114[03] are handled, support for other
1320*74a4d8c2SCharles.Forsyth 	 * controllers can be added as needed.
1321*74a4d8c2SCharles.Forsyth 	 */
1322*74a4d8c2SCharles.Forsyth 	sromr(ctlr, 0);
1323*74a4d8c2SCharles.Forsyth 	if(ctlr->srom == nil)
1324*74a4d8c2SCharles.Forsyth 		ctlr->srom = malloc((1<<ctlr->sromsz)*sizeof(ushort));
1325*74a4d8c2SCharles.Forsyth 	for(i = 0; i < (1<<ctlr->sromsz); i++){
1326*74a4d8c2SCharles.Forsyth 		x = sromr(ctlr, i);
1327*74a4d8c2SCharles.Forsyth 		ctlr->srom[2*i] = x;
1328*74a4d8c2SCharles.Forsyth 		ctlr->srom[2*i+1] = x>>8;
1329*74a4d8c2SCharles.Forsyth 	}
1330*74a4d8c2SCharles.Forsyth 
1331*74a4d8c2SCharles.Forsyth 	if(DEBUG){
1332*74a4d8c2SCharles.Forsyth 		print("srom:");
1333*74a4d8c2SCharles.Forsyth 		for(i = 0; i < ((1<<ctlr->sromsz)*sizeof(ushort)); i++){
1334*74a4d8c2SCharles.Forsyth 			if(i && ((i & 0x0F) == 0))
1335*74a4d8c2SCharles.Forsyth 				print("\n     ");
1336*74a4d8c2SCharles.Forsyth 			print(" %2.2uX", ctlr->srom[i]);
1337*74a4d8c2SCharles.Forsyth 		}
1338*74a4d8c2SCharles.Forsyth 		print("\n");
1339*74a4d8c2SCharles.Forsyth 	}
1340*74a4d8c2SCharles.Forsyth 
1341*74a4d8c2SCharles.Forsyth 	/*
1342*74a4d8c2SCharles.Forsyth 	 * There are 2 SROM layouts:
1343*74a4d8c2SCharles.Forsyth 	 *	e.g. Digital EtherWORKS	station address at offset 20;
1344*74a4d8c2SCharles.Forsyth 	 *				this complies with the 21140A SROM
1345*74a4d8c2SCharles.Forsyth 	 *				application note from Digital;
1346*74a4d8c2SCharles.Forsyth 	 * 	e.g. SMC9332		station address at offset 0 followed by
1347*74a4d8c2SCharles.Forsyth 	 *				2 additional bytes, repeated at offset
1348*74a4d8c2SCharles.Forsyth 	 *				6; the 8 bytes are also repeated in
1349*74a4d8c2SCharles.Forsyth 	 *				reverse order at offset 8.
1350*74a4d8c2SCharles.Forsyth 	 * To check which it is, read the SROM and check for the repeating
1351*74a4d8c2SCharles.Forsyth 	 * patterns of the non-compliant cards; if that fails use the one at
1352*74a4d8c2SCharles.Forsyth 	 * offset 20.
1353*74a4d8c2SCharles.Forsyth 	 */
1354*74a4d8c2SCharles.Forsyth 	ctlr->sromea = ctlr->srom;
1355*74a4d8c2SCharles.Forsyth 	for(i = 0; i < 8; i++){
1356*74a4d8c2SCharles.Forsyth 		x = ctlr->srom[i];
1357*74a4d8c2SCharles.Forsyth 		if(x != ctlr->srom[15-i] || x != ctlr->srom[16+i]){
1358*74a4d8c2SCharles.Forsyth 			ctlr->sromea = &ctlr->srom[20];
1359*74a4d8c2SCharles.Forsyth 			break;
1360*74a4d8c2SCharles.Forsyth 		}
1361*74a4d8c2SCharles.Forsyth 	}
1362*74a4d8c2SCharles.Forsyth 
1363*74a4d8c2SCharles.Forsyth 	/*
1364*74a4d8c2SCharles.Forsyth 	 * Fake up the SROM for the PNIC.
1365*74a4d8c2SCharles.Forsyth 	 * It looks like a 21140 with a PHY.
1366*74a4d8c2SCharles.Forsyth 	 * The MAC address is byte-swapped in the orginal SROM data.
1367*74a4d8c2SCharles.Forsyth 	 */
1368*74a4d8c2SCharles.Forsyth 	if(ctlr->id == Pnic){
1369*74a4d8c2SCharles.Forsyth 		memmove(&ctlr->srom[20], leafpnic, sizeof(leafpnic));
1370*74a4d8c2SCharles.Forsyth 		for(i = 0; i < Eaddrlen; i += 2){
1371*74a4d8c2SCharles.Forsyth 			ctlr->srom[20+i] = ctlr->srom[i+1];
1372*74a4d8c2SCharles.Forsyth 			ctlr->srom[20+i+1] = ctlr->srom[i];
1373*74a4d8c2SCharles.Forsyth 		}
1374*74a4d8c2SCharles.Forsyth 	}
1375*74a4d8c2SCharles.Forsyth 
1376*74a4d8c2SCharles.Forsyth 	/*
1377*74a4d8c2SCharles.Forsyth 	 * Next, try to find the info leaf in the SROM for media detection.
1378*74a4d8c2SCharles.Forsyth 	 * If it's a non-conforming card try to match the vendor ethernet code
1379*74a4d8c2SCharles.Forsyth 	 * and point p at a fake info leaf with compact 21140 entries.
1380*74a4d8c2SCharles.Forsyth 	 */
1381*74a4d8c2SCharles.Forsyth 	if(ctlr->sromea == ctlr->srom){
1382*74a4d8c2SCharles.Forsyth 		p = nil;
1383*74a4d8c2SCharles.Forsyth 		for(i = 0; leaf21140[i] != nil; i++){
1384*74a4d8c2SCharles.Forsyth 			if(memcmp(leaf21140[i], ctlr->sromea, 3) == 0){
1385*74a4d8c2SCharles.Forsyth 				p = &leaf21140[i][4];
1386*74a4d8c2SCharles.Forsyth 				break;
1387*74a4d8c2SCharles.Forsyth 			}
1388*74a4d8c2SCharles.Forsyth 		}
1389*74a4d8c2SCharles.Forsyth 		if(p == nil)
1390*74a4d8c2SCharles.Forsyth 			return -1;
1391*74a4d8c2SCharles.Forsyth 	}
1392*74a4d8c2SCharles.Forsyth 	else
1393*74a4d8c2SCharles.Forsyth 		p = &ctlr->srom[(ctlr->srom[28]<<8)|ctlr->srom[27]];
1394*74a4d8c2SCharles.Forsyth 
1395*74a4d8c2SCharles.Forsyth 	/*
1396*74a4d8c2SCharles.Forsyth 	 * Set up the info needed for later media detection.
1397*74a4d8c2SCharles.Forsyth 	 * For the 21140, set the general-purpose mask in CSR12.
1398*74a4d8c2SCharles.Forsyth 	 * The info block entries are stored in order of increasing
1399*74a4d8c2SCharles.Forsyth 	 * precedence, so detection will work backwards through the
1400*74a4d8c2SCharles.Forsyth 	 * stored indexes into ctlr->srom.
1401*74a4d8c2SCharles.Forsyth 	 * If an entry is found which matches the selected connection
1402*74a4d8c2SCharles.Forsyth 	 * type, save the index. Otherwise, start at the last entry.
1403*74a4d8c2SCharles.Forsyth 	 * If any MII entries are found (type 1 and 3 blocks), scan
1404*74a4d8c2SCharles.Forsyth 	 * for PHYs.
1405*74a4d8c2SCharles.Forsyth 	 */
1406*74a4d8c2SCharles.Forsyth 	ctlr->leaf = p;
1407*74a4d8c2SCharles.Forsyth 	ctlr->sct = *p++;
1408*74a4d8c2SCharles.Forsyth 	ctlr->sct |= *p++<<8;
1409*74a4d8c2SCharles.Forsyth 	if(ctlr->id != Tulip3 && ctlr->id != Tulip1){
1410*74a4d8c2SCharles.Forsyth 		csr32w(ctlr, 12, Gpc|*p++);
1411*74a4d8c2SCharles.Forsyth 		delay(200);
1412*74a4d8c2SCharles.Forsyth 	}
1413*74a4d8c2SCharles.Forsyth 	ctlr->k = *p++;
1414*74a4d8c2SCharles.Forsyth 	if(ctlr->k >= nelem(ctlr->infoblock))
1415*74a4d8c2SCharles.Forsyth 		ctlr->k = nelem(ctlr->infoblock)-1;
1416*74a4d8c2SCharles.Forsyth 	ctlr->sctk = ctlr->k-1;
1417*74a4d8c2SCharles.Forsyth 	phy = 0;
1418*74a4d8c2SCharles.Forsyth 	for(k = 0; k < ctlr->k; k++){
1419*74a4d8c2SCharles.Forsyth 		ctlr->infoblock[k] = p;
1420*74a4d8c2SCharles.Forsyth 		if(ctlr->id == Tulip1){
1421*74a4d8c2SCharles.Forsyth 			debug("type21041: 0x%2.2uX\n", p[0]);
1422*74a4d8c2SCharles.Forsyth 			if(ctlr->sct != 0x0800 && *p == (ctlr->sct & 0xFF))
1423*74a4d8c2SCharles.Forsyth 				ctlr->sctk = k;
1424*74a4d8c2SCharles.Forsyth 			if(*p & 0x40)
1425*74a4d8c2SCharles.Forsyth 				p += 7;
1426*74a4d8c2SCharles.Forsyth 			else
1427*74a4d8c2SCharles.Forsyth 				p += 1;
1428*74a4d8c2SCharles.Forsyth 		}
1429*74a4d8c2SCharles.Forsyth 		/*
1430*74a4d8c2SCharles.Forsyth 		 * The RAMIX PMC665 has a badly-coded SROM,
1431*74a4d8c2SCharles.Forsyth 		 * hence the test for 21143 and type 3.
1432*74a4d8c2SCharles.Forsyth 		 */
1433*74a4d8c2SCharles.Forsyth 		else if((*p & 0x80) || (ctlr->id == Tulip3 && *(p+1) == 3)){
1434*74a4d8c2SCharles.Forsyth 			*p |= 0x80;
1435*74a4d8c2SCharles.Forsyth 			if(*(p+1) == 1 || *(p+1) == 3)
1436*74a4d8c2SCharles.Forsyth 				phy = 1;
1437*74a4d8c2SCharles.Forsyth 			if(*(p+1) == 5)
1438*74a4d8c2SCharles.Forsyth 				ctlr->type5block = p;
1439*74a4d8c2SCharles.Forsyth 			p += (*p & ~0x80)+1;
1440*74a4d8c2SCharles.Forsyth 		}
1441*74a4d8c2SCharles.Forsyth 		else{
1442*74a4d8c2SCharles.Forsyth 			debug("type0: 0x%2.2uX 0x%2.2uX 0x%2.2uX 0x%2.2uX\n",
1443*74a4d8c2SCharles.Forsyth 				p[0], p[1], p[2], p[3]);
1444*74a4d8c2SCharles.Forsyth 			if(ctlr->sct != 0x0800 && *p == (ctlr->sct & 0xFF))
1445*74a4d8c2SCharles.Forsyth 				ctlr->sctk = k;
1446*74a4d8c2SCharles.Forsyth 			p += 4;
1447*74a4d8c2SCharles.Forsyth 		}
1448*74a4d8c2SCharles.Forsyth 	}
1449*74a4d8c2SCharles.Forsyth 	ctlr->curk = ctlr->sctk;
1450*74a4d8c2SCharles.Forsyth 	debug("sct 0x%uX medium 0x%uX k %d curk %d phy %d\n",
1451*74a4d8c2SCharles.Forsyth 		ctlr->sct, ctlr->medium, ctlr->k, ctlr->curk, phy);
1452*74a4d8c2SCharles.Forsyth 
1453*74a4d8c2SCharles.Forsyth 	if(phy){
1454*74a4d8c2SCharles.Forsyth 		x = 0;
1455*74a4d8c2SCharles.Forsyth 		for(k = 0; k < nelem(ctlr->phy); k++){
1456*74a4d8c2SCharles.Forsyth 			if((oui = miir(ctlr, k, 2)) == -1 || oui == 0)
1457*74a4d8c2SCharles.Forsyth 				continue;
1458*74a4d8c2SCharles.Forsyth 			if(DEBUG){
1459*74a4d8c2SCharles.Forsyth 				oui = (oui & 0x3FF)<<6;
1460*74a4d8c2SCharles.Forsyth 				oui |= miir(ctlr, k, 3)>>10;
1461*74a4d8c2SCharles.Forsyth 				miir(ctlr, k, 1);
1462*74a4d8c2SCharles.Forsyth 				debug("phy%d: index %d oui %uX reg1 %uX\n",
1463*74a4d8c2SCharles.Forsyth 					x, k, oui, miir(ctlr, k, 1));
1464*74a4d8c2SCharles.Forsyth 				USED(oui);
1465*74a4d8c2SCharles.Forsyth 			}
1466*74a4d8c2SCharles.Forsyth 			ctlr->phy[x] = k;
1467*74a4d8c2SCharles.Forsyth 		}
1468*74a4d8c2SCharles.Forsyth 	}
1469*74a4d8c2SCharles.Forsyth 
1470*74a4d8c2SCharles.Forsyth 	ctlr->fd = 0;
1471*74a4d8c2SCharles.Forsyth 	ctlr->medium = -1;
1472*74a4d8c2SCharles.Forsyth 
1473*74a4d8c2SCharles.Forsyth 	return 0;
1474*74a4d8c2SCharles.Forsyth }
1475*74a4d8c2SCharles.Forsyth 
1476*74a4d8c2SCharles.Forsyth static void
dec2114xpci(void)1477*74a4d8c2SCharles.Forsyth dec2114xpci(void)
1478*74a4d8c2SCharles.Forsyth {
1479*74a4d8c2SCharles.Forsyth 	Ctlr *ctlr;
1480*74a4d8c2SCharles.Forsyth 	Pcidev *p;
1481*74a4d8c2SCharles.Forsyth 	int x;
1482*74a4d8c2SCharles.Forsyth 
1483*74a4d8c2SCharles.Forsyth 	p = nil;
1484*74a4d8c2SCharles.Forsyth 	while(p = pcimatch(p, 0, 0)){
1485*74a4d8c2SCharles.Forsyth 		if(p->ccrb != 0x02 || p->ccru != 0)
1486*74a4d8c2SCharles.Forsyth 			continue;
1487*74a4d8c2SCharles.Forsyth 		switch((p->did<<16)|p->vid){
1488*74a4d8c2SCharles.Forsyth 		default:
1489*74a4d8c2SCharles.Forsyth 			continue;
1490*74a4d8c2SCharles.Forsyth 
1491*74a4d8c2SCharles.Forsyth 		case Tulip3:			/* 21143 */
1492*74a4d8c2SCharles.Forsyth 			/*
1493*74a4d8c2SCharles.Forsyth 			 * Exit sleep mode.
1494*74a4d8c2SCharles.Forsyth 			 */
1495*74a4d8c2SCharles.Forsyth 			x = pcicfgr32(p, 0x40);
1496*74a4d8c2SCharles.Forsyth 			x &= ~0xC0000000;
1497*74a4d8c2SCharles.Forsyth 			pcicfgw32(p, 0x40, x);
1498*74a4d8c2SCharles.Forsyth 			/*FALLTHROUGH*/
1499*74a4d8c2SCharles.Forsyth 
1500*74a4d8c2SCharles.Forsyth 		case Pnic:			/* PNIC */
1501*74a4d8c2SCharles.Forsyth 		case Pnic2:			/* PNIC-II */
1502*74a4d8c2SCharles.Forsyth 		case Tulip0:			/* 21140 */
1503*74a4d8c2SCharles.Forsyth 		case Tulip1:			/* 21041 */
1504*74a4d8c2SCharles.Forsyth 			break;
1505*74a4d8c2SCharles.Forsyth 		}
1506*74a4d8c2SCharles.Forsyth 
1507*74a4d8c2SCharles.Forsyth 		/*
1508*74a4d8c2SCharles.Forsyth 		 * bar[0] is the I/O port register address and
1509*74a4d8c2SCharles.Forsyth 		 * bar[1] is the memory-mapped register address.
1510*74a4d8c2SCharles.Forsyth 		 */
1511*74a4d8c2SCharles.Forsyth 		ctlr = malloc(sizeof(Ctlr));
1512*74a4d8c2SCharles.Forsyth 		ctlr->port = p->mem[0].bar & ~0x01;
1513*74a4d8c2SCharles.Forsyth 		ctlr->pcidev = p;
1514*74a4d8c2SCharles.Forsyth 		ctlr->id = (p->did<<16)|p->vid;
1515*74a4d8c2SCharles.Forsyth 		debug("2114x: type 0x%8.8uX rev 0x%4.4uX at port 0x%4.4uX\n",
1516*74a4d8c2SCharles.Forsyth 			ctlr->id, p->rid, ctlr->port);
1517*74a4d8c2SCharles.Forsyth 
1518*74a4d8c2SCharles.Forsyth 		/*
1519*74a4d8c2SCharles.Forsyth 		 * Some cards (e.g. ANA-6910FX) seem to need the Ps bit
1520*74a4d8c2SCharles.Forsyth 		 * set or they don't always work right after a hardware
1521*74a4d8c2SCharles.Forsyth 		 * reset.
1522*74a4d8c2SCharles.Forsyth 		 */
1523*74a4d8c2SCharles.Forsyth 		csr32w(ctlr, 6, Mbo|Ps);
1524*74a4d8c2SCharles.Forsyth 		softreset(ctlr);
1525*74a4d8c2SCharles.Forsyth 
1526*74a4d8c2SCharles.Forsyth 		if(srom(ctlr)){
1527*74a4d8c2SCharles.Forsyth 			free(ctlr);
1528*74a4d8c2SCharles.Forsyth 			break;
1529*74a4d8c2SCharles.Forsyth 		}
1530*74a4d8c2SCharles.Forsyth 
1531*74a4d8c2SCharles.Forsyth 		switch(ctlr->id){
1532*74a4d8c2SCharles.Forsyth 		default:
1533*74a4d8c2SCharles.Forsyth 			break;
1534*74a4d8c2SCharles.Forsyth 
1535*74a4d8c2SCharles.Forsyth 		case Pnic:			/* PNIC */
1536*74a4d8c2SCharles.Forsyth 			/*
1537*74a4d8c2SCharles.Forsyth 			 * Turn off the jabber timer.
1538*74a4d8c2SCharles.Forsyth 			 */
1539*74a4d8c2SCharles.Forsyth 			csr32w(ctlr, 15, 0x00000001);
1540*74a4d8c2SCharles.Forsyth 			break;
1541*74a4d8c2SCharles.Forsyth 		}
1542*74a4d8c2SCharles.Forsyth 
1543*74a4d8c2SCharles.Forsyth 		if(ctlrhead != nil)
1544*74a4d8c2SCharles.Forsyth 			ctlrtail->next = ctlr;
1545*74a4d8c2SCharles.Forsyth 		else
1546*74a4d8c2SCharles.Forsyth 			ctlrhead = ctlr;
1547*74a4d8c2SCharles.Forsyth 		ctlrtail = ctlr;
1548*74a4d8c2SCharles.Forsyth 	}
1549*74a4d8c2SCharles.Forsyth }
1550*74a4d8c2SCharles.Forsyth 
1551*74a4d8c2SCharles.Forsyth static void
detach(Ether * ether)1552*74a4d8c2SCharles.Forsyth detach(Ether* ether)
1553*74a4d8c2SCharles.Forsyth {
1554*74a4d8c2SCharles.Forsyth 	softreset(ether->ctlr);
1555*74a4d8c2SCharles.Forsyth }
1556*74a4d8c2SCharles.Forsyth 
1557*74a4d8c2SCharles.Forsyth int
ether2114xreset(Ether * ether)1558*74a4d8c2SCharles.Forsyth ether2114xreset(Ether* ether)
1559*74a4d8c2SCharles.Forsyth {
1560*74a4d8c2SCharles.Forsyth 	Ctlr *ctlr;
1561*74a4d8c2SCharles.Forsyth 	int i, x;
1562*74a4d8c2SCharles.Forsyth 	uchar ea[Eaddrlen];
1563*74a4d8c2SCharles.Forsyth 	static int scandone;
1564*74a4d8c2SCharles.Forsyth 
1565*74a4d8c2SCharles.Forsyth 	if(scandone == 0){
1566*74a4d8c2SCharles.Forsyth 		dec2114xpci();
1567*74a4d8c2SCharles.Forsyth 		scandone = 1;
1568*74a4d8c2SCharles.Forsyth 	}
1569*74a4d8c2SCharles.Forsyth 
1570*74a4d8c2SCharles.Forsyth 	/*
1571*74a4d8c2SCharles.Forsyth 	 * Any adapter matches if no ether->port is supplied,
1572*74a4d8c2SCharles.Forsyth 	 * otherwise the ports must match.
1573*74a4d8c2SCharles.Forsyth 	 */
1574*74a4d8c2SCharles.Forsyth 	for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){
1575*74a4d8c2SCharles.Forsyth 		if(ctlr->active)
1576*74a4d8c2SCharles.Forsyth 			continue;
1577*74a4d8c2SCharles.Forsyth 		if(ether->port == 0 || ether->port == ctlr->port){
1578*74a4d8c2SCharles.Forsyth 			ctlr->active = 1;
1579*74a4d8c2SCharles.Forsyth 			break;
1580*74a4d8c2SCharles.Forsyth 		}
1581*74a4d8c2SCharles.Forsyth 	}
1582*74a4d8c2SCharles.Forsyth 	if(ctlr == nil)
1583*74a4d8c2SCharles.Forsyth 		return -1;
1584*74a4d8c2SCharles.Forsyth 
1585*74a4d8c2SCharles.Forsyth 	ether->ctlr = ctlr;
1586*74a4d8c2SCharles.Forsyth 	ether->port = ctlr->port;
1587*74a4d8c2SCharles.Forsyth 	ether->irq = ctlr->pcidev->intl;
1588*74a4d8c2SCharles.Forsyth 	ether->tbdf = ctlr->pcidev->tbdf;
1589*74a4d8c2SCharles.Forsyth 
1590*74a4d8c2SCharles.Forsyth 	/*
1591*74a4d8c2SCharles.Forsyth 	 * Check if the adapter's station address is to be overridden.
1592*74a4d8c2SCharles.Forsyth 	 * If not, read it from the EEPROM and set in ether->ea prior to
1593*74a4d8c2SCharles.Forsyth 	 * loading the station address in the hardware.
1594*74a4d8c2SCharles.Forsyth 	 */
1595*74a4d8c2SCharles.Forsyth 	memset(ea, 0, Eaddrlen);
1596*74a4d8c2SCharles.Forsyth 	if(memcmp(ea, ether->ea, Eaddrlen) == 0)
1597*74a4d8c2SCharles.Forsyth 		memmove(ether->ea, ctlr->sromea, Eaddrlen);
1598*74a4d8c2SCharles.Forsyth 
1599*74a4d8c2SCharles.Forsyth 	/*
1600*74a4d8c2SCharles.Forsyth 	 * Look for a medium override in case there's no autonegotiation
1601*74a4d8c2SCharles.Forsyth 	 * (no MII) or the autonegotiation fails.
1602*74a4d8c2SCharles.Forsyth 	 */
1603*74a4d8c2SCharles.Forsyth 	for(i = 0; i < ether->nopt; i++){
1604*74a4d8c2SCharles.Forsyth 		if(cistrcmp(ether->opt[i], "FD") == 0){
1605*74a4d8c2SCharles.Forsyth 			ctlr->fd = 1;
1606*74a4d8c2SCharles.Forsyth 			continue;
1607*74a4d8c2SCharles.Forsyth 		}
1608*74a4d8c2SCharles.Forsyth 		for(x = 0; x < nelem(mediatable); x++){
1609*74a4d8c2SCharles.Forsyth 			debug("compare <%s> <%s>\n", mediatable[x],
1610*74a4d8c2SCharles.Forsyth 				ether->opt[i]);
1611*74a4d8c2SCharles.Forsyth 			if(cistrcmp(mediatable[x], ether->opt[i]))
1612*74a4d8c2SCharles.Forsyth 				continue;
1613*74a4d8c2SCharles.Forsyth 			ctlr->medium = x;
1614*74a4d8c2SCharles.Forsyth 
1615*74a4d8c2SCharles.Forsyth 			switch(ctlr->medium){
1616*74a4d8c2SCharles.Forsyth 			default:
1617*74a4d8c2SCharles.Forsyth 				ctlr->fd = 0;
1618*74a4d8c2SCharles.Forsyth 				break;
1619*74a4d8c2SCharles.Forsyth 
1620*74a4d8c2SCharles.Forsyth 			case 0x04:		/* 10BASE-TFD */
1621*74a4d8c2SCharles.Forsyth 			case 0x05:		/* 100BASE-TXFD */
1622*74a4d8c2SCharles.Forsyth 			case 0x08:		/* 100BASE-FXFD */
1623*74a4d8c2SCharles.Forsyth 				ctlr->fd = 1;
1624*74a4d8c2SCharles.Forsyth 				break;
1625*74a4d8c2SCharles.Forsyth 			}
1626*74a4d8c2SCharles.Forsyth 			break;
1627*74a4d8c2SCharles.Forsyth 		}
1628*74a4d8c2SCharles.Forsyth 	}
1629*74a4d8c2SCharles.Forsyth 
1630*74a4d8c2SCharles.Forsyth 	/*
1631*74a4d8c2SCharles.Forsyth 	 * Determine media.
1632*74a4d8c2SCharles.Forsyth 	 */
1633*74a4d8c2SCharles.Forsyth 	ctlr->mbps = media(ether, 1);
1634*74a4d8c2SCharles.Forsyth 
1635*74a4d8c2SCharles.Forsyth 	/*
1636*74a4d8c2SCharles.Forsyth 	 * Initialise descriptor rings, ethernet address.
1637*74a4d8c2SCharles.Forsyth 	 */
1638*74a4d8c2SCharles.Forsyth 	ctlr->nrdr = Nrde;
1639*74a4d8c2SCharles.Forsyth 	ctlr->ntdr = Ntde;
1640*74a4d8c2SCharles.Forsyth 	pcisetbme(ctlr->pcidev);
1641*74a4d8c2SCharles.Forsyth 	ctlrinit(ether);
1642*74a4d8c2SCharles.Forsyth 
1643*74a4d8c2SCharles.Forsyth 	/*
1644*74a4d8c2SCharles.Forsyth 	 * Linkage to the generic ethernet driver.
1645*74a4d8c2SCharles.Forsyth 	 */
1646*74a4d8c2SCharles.Forsyth 	ether->attach = attach;
1647*74a4d8c2SCharles.Forsyth 	ether->transmit = transmit;
1648*74a4d8c2SCharles.Forsyth 	ether->interrupt = interrupt;
1649*74a4d8c2SCharles.Forsyth 	ether->detach = detach;
1650*74a4d8c2SCharles.Forsyth 
1651*74a4d8c2SCharles.Forsyth 	return 0;
1652*74a4d8c2SCharles.Forsyth }
1653