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 = ðer->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 = ðer->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