xref: /plan9/sys/src/9/kw/ethermii.c (revision eb2d6162df2e9aaa5669e79b7f9c5c02f4ef89a4)
1154abd99SDavid du Colombier #include "u.h"
2154abd99SDavid du Colombier #include "../port/lib.h"
3154abd99SDavid du Colombier #include "mem.h"
4154abd99SDavid du Colombier #include "dat.h"
5154abd99SDavid du Colombier #include "fns.h"
6154abd99SDavid du Colombier #include "io.h"
7154abd99SDavid du Colombier #include "../port/error.h"
8154abd99SDavid du Colombier #include "../port/netif.h"
9154abd99SDavid du Colombier 
10154abd99SDavid du Colombier #include "etherif.h"
11154abd99SDavid du Colombier #include "ethermii.h"
12154abd99SDavid du Colombier 
13154abd99SDavid du Colombier int
mii(Mii * mii,int mask)14154abd99SDavid du Colombier mii(Mii* mii, int mask)
15154abd99SDavid du Colombier {
16154abd99SDavid du Colombier 	MiiPhy *miiphy;
17154abd99SDavid du Colombier 	int bit, oui, phyno, r, rmask;
18154abd99SDavid du Colombier 
19154abd99SDavid du Colombier 	/*
20154abd99SDavid du Colombier 	 * Probe through mii for PHYs in mask;
21154abd99SDavid du Colombier 	 * return the mask of those found in the current probe.
22154abd99SDavid du Colombier 	 * If the PHY has not already been probed, update
23154abd99SDavid du Colombier 	 * the Mii information.
24154abd99SDavid du Colombier 	 */
25154abd99SDavid du Colombier 	rmask = 0;
26154abd99SDavid du Colombier 	for(phyno = 0; phyno < NMiiPhy; phyno++){
27154abd99SDavid du Colombier 		bit = 1<<phyno;
28154abd99SDavid du Colombier 		if(!(mask & bit))
29154abd99SDavid du Colombier 			continue;
30154abd99SDavid du Colombier 		if(mii->mask & bit){
31154abd99SDavid du Colombier 			rmask |= bit;
32154abd99SDavid du Colombier 			continue;
33154abd99SDavid du Colombier 		}
34154abd99SDavid du Colombier 		if(mii->mir(mii, phyno, Bmsr) == -1)
35154abd99SDavid du Colombier 			continue;
36154abd99SDavid du Colombier 		r = mii->mir(mii, phyno, Phyidr1);
37154abd99SDavid du Colombier 		oui = (r & 0x3FFF)<<6;
38154abd99SDavid du Colombier 		r = mii->mir(mii, phyno, Phyidr2);
39154abd99SDavid du Colombier 		oui |= r>>10;
40154abd99SDavid du Colombier 		if(oui == 0xFFFFF || oui == 0)
41154abd99SDavid du Colombier 			continue;
42154abd99SDavid du Colombier 
43154abd99SDavid du Colombier 		if((miiphy = malloc(sizeof(MiiPhy))) == nil)
44154abd99SDavid du Colombier 			continue;
45154abd99SDavid du Colombier 
46154abd99SDavid du Colombier 		miiphy->mii = mii;
47154abd99SDavid du Colombier 		miiphy->oui = oui;
48154abd99SDavid du Colombier 		miiphy->phyno = phyno;
49154abd99SDavid du Colombier 
50154abd99SDavid du Colombier 		miiphy->anar = ~0;
51154abd99SDavid du Colombier 		miiphy->fc = ~0;
52154abd99SDavid du Colombier 		miiphy->mscr = ~0;
53154abd99SDavid du Colombier 
54154abd99SDavid du Colombier 		mii->phy[phyno] = miiphy;
55154abd99SDavid du Colombier 		if(mii->curphy == nil)
56154abd99SDavid du Colombier 			mii->curphy = miiphy;
57154abd99SDavid du Colombier 		mii->mask |= bit;
58154abd99SDavid du Colombier 		mii->nphy++;
59154abd99SDavid du Colombier 
60154abd99SDavid du Colombier 		rmask |= bit;
61154abd99SDavid du Colombier 	}
62154abd99SDavid du Colombier 	return rmask;
63154abd99SDavid du Colombier }
64154abd99SDavid du Colombier 
65154abd99SDavid du Colombier int
miimir(Mii * mii,int r)66154abd99SDavid du Colombier miimir(Mii* mii, int r)
67154abd99SDavid du Colombier {
68154abd99SDavid du Colombier 	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
69154abd99SDavid du Colombier 		return -1;
70154abd99SDavid du Colombier 	return mii->mir(mii, mii->curphy->phyno, r);
71154abd99SDavid du Colombier }
72154abd99SDavid du Colombier 
73154abd99SDavid du Colombier int
miimiw(Mii * mii,int r,int data)74154abd99SDavid du Colombier miimiw(Mii* mii, int r, int data)
75154abd99SDavid du Colombier {
76154abd99SDavid du Colombier 	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
77154abd99SDavid du Colombier 		return -1;
78154abd99SDavid du Colombier 	return mii->miw(mii, mii->curphy->phyno, r, data);
79154abd99SDavid du Colombier }
80154abd99SDavid du Colombier 
81154abd99SDavid du Colombier int
miireset(Mii * mii)82154abd99SDavid du Colombier miireset(Mii* mii)
83154abd99SDavid du Colombier {
84*eb2d6162SDavid du Colombier 	int bmcr, phyno;
85154abd99SDavid du Colombier 
86154abd99SDavid du Colombier 	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
87154abd99SDavid du Colombier 		return -1;
88*eb2d6162SDavid du Colombier 	phyno = mii->curphy->phyno;
89*eb2d6162SDavid du Colombier 	bmcr = mii->mir(mii, phyno, Bmcr);
90154abd99SDavid du Colombier 	bmcr |= BmcrR;
91*eb2d6162SDavid du Colombier 	mii->miw(mii, phyno, Bmcr, bmcr);
92*eb2d6162SDavid du Colombier 
93*eb2d6162SDavid du Colombier //	microdelay(1);
94*eb2d6162SDavid du Colombier 	while(mii->mir(mii, phyno, Bmcr) & BmcrR)
95*eb2d6162SDavid du Colombier 		;
96154abd99SDavid du Colombier 
97154abd99SDavid du Colombier 	return 0;
98154abd99SDavid du Colombier }
99154abd99SDavid du Colombier 
100154abd99SDavid du Colombier int
miiane(Mii * mii,int a,int p,int e)101154abd99SDavid du Colombier miiane(Mii* mii, int a, int p, int e)
102154abd99SDavid du Colombier {
103154abd99SDavid du Colombier 	int anar, bmsr, mscr, r, phyno;
104154abd99SDavid du Colombier 
105154abd99SDavid du Colombier 	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
106154abd99SDavid du Colombier 		return -1;
107154abd99SDavid du Colombier 	phyno = mii->curphy->phyno;
108154abd99SDavid du Colombier 
109154abd99SDavid du Colombier 	bmsr = mii->mir(mii, phyno, Bmsr);
110154abd99SDavid du Colombier 	if(!(bmsr & BmsrAna))
111154abd99SDavid du Colombier 		return -1;
112154abd99SDavid du Colombier 
113154abd99SDavid du Colombier 	if(a != ~0)
114154abd99SDavid du Colombier 		anar = (AnaTXFD|AnaTXHD|Ana10FD|Ana10HD) & a;
115154abd99SDavid du Colombier 	else if(mii->curphy->anar != ~0)
116154abd99SDavid du Colombier 		anar = mii->curphy->anar;
117154abd99SDavid du Colombier 	else{
118154abd99SDavid du Colombier 		anar = mii->mir(mii, phyno, Anar);
119154abd99SDavid du Colombier 		anar &= ~(AnaAP|AnaP|AnaT4|AnaTXFD|AnaTXHD|Ana10FD|Ana10HD);
120154abd99SDavid du Colombier 		if(bmsr & Bmsr10THD)
121154abd99SDavid du Colombier 			anar |= Ana10HD;
122154abd99SDavid du Colombier 		if(bmsr & Bmsr10TFD)
123154abd99SDavid du Colombier 			anar |= Ana10FD;
124154abd99SDavid du Colombier 		if(bmsr & Bmsr100TXHD)
125154abd99SDavid du Colombier 			anar |= AnaTXHD;
126154abd99SDavid du Colombier 		if(bmsr & Bmsr100TXFD)
127154abd99SDavid du Colombier 			anar |= AnaTXFD;
128154abd99SDavid du Colombier 	}
129154abd99SDavid du Colombier 	mii->curphy->anar = anar;
130154abd99SDavid du Colombier 
131154abd99SDavid du Colombier 	if(p != ~0)
132154abd99SDavid du Colombier 		anar |= (AnaAP|AnaP) & p;
133154abd99SDavid du Colombier 	else if(mii->curphy->fc != ~0)
134154abd99SDavid du Colombier 		anar |= mii->curphy->fc;
135154abd99SDavid du Colombier 	mii->curphy->fc = (AnaAP|AnaP) & anar;
136154abd99SDavid du Colombier 
137154abd99SDavid du Colombier 	if(bmsr & BmsrEs){
138154abd99SDavid du Colombier 		mscr = mii->mir(mii, phyno, Mscr);
139154abd99SDavid du Colombier 		mscr &= ~(Mscr1000TFD|Mscr1000THD);
140154abd99SDavid du Colombier 		if(e != ~0)
141154abd99SDavid du Colombier 			mscr |= (Mscr1000TFD|Mscr1000THD) & e;
142154abd99SDavid du Colombier 		else if(mii->curphy->mscr != ~0)
143154abd99SDavid du Colombier 			mscr = mii->curphy->mscr;
144154abd99SDavid du Colombier 		else{
145154abd99SDavid du Colombier 			r = mii->mir(mii, phyno, Esr);
146154abd99SDavid du Colombier 			if(r & Esr1000THD)
147154abd99SDavid du Colombier 				mscr |= Mscr1000THD;
148154abd99SDavid du Colombier 			if(r & Esr1000TFD)
149154abd99SDavid du Colombier 				mscr |= Mscr1000TFD;
150154abd99SDavid du Colombier 		}
151154abd99SDavid du Colombier 		mii->curphy->mscr = mscr;
152154abd99SDavid du Colombier 		mii->miw(mii, phyno, Mscr, mscr);
153154abd99SDavid du Colombier 	}
154154abd99SDavid du Colombier 	mii->miw(mii, phyno, Anar, anar);
155154abd99SDavid du Colombier 
156154abd99SDavid du Colombier 	r = mii->mir(mii, phyno, Bmcr);
157154abd99SDavid du Colombier 	if(!(r & BmcrR)){
158154abd99SDavid du Colombier 		r |= BmcrAne|BmcrRan;
159154abd99SDavid du Colombier 		mii->miw(mii, phyno, Bmcr, r);
160154abd99SDavid du Colombier 	}
161154abd99SDavid du Colombier 
162154abd99SDavid du Colombier 	return 0;
163154abd99SDavid du Colombier }
164154abd99SDavid du Colombier 
165154abd99SDavid du Colombier int
miistatus(Mii * mii)166154abd99SDavid du Colombier miistatus(Mii* mii)
167154abd99SDavid du Colombier {
168154abd99SDavid du Colombier 	MiiPhy *phy;
169154abd99SDavid du Colombier 	int anlpar, bmsr, p, r, phyno;
170154abd99SDavid du Colombier 
171154abd99SDavid du Colombier 	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
172154abd99SDavid du Colombier 		return -1;
173154abd99SDavid du Colombier 	phy = mii->curphy;
174154abd99SDavid du Colombier 	phyno = phy->phyno;
175154abd99SDavid du Colombier 
176154abd99SDavid du Colombier 	/*
177154abd99SDavid du Colombier 	 * Check Auto-Negotiation is complete and link is up.
178154abd99SDavid du Colombier 	 * (Read status twice as the Ls bit is sticky).
179154abd99SDavid du Colombier 	 */
180154abd99SDavid du Colombier 	bmsr = mii->mir(mii, phyno, Bmsr);
181154abd99SDavid du Colombier 	if(!(bmsr & (BmsrAnc|BmsrAna))) {
182154abd99SDavid du Colombier 		// print("miistatus: auto-neg incomplete\n");
183154abd99SDavid du Colombier 		return -1;
184154abd99SDavid du Colombier 	}
185154abd99SDavid du Colombier 
186154abd99SDavid du Colombier 	bmsr = mii->mir(mii, phyno, Bmsr);
187154abd99SDavid du Colombier 	if(!(bmsr & BmsrLs)){
188154abd99SDavid du Colombier 		// print("miistatus: link down\n");
189154abd99SDavid du Colombier 		phy->link = 0;
190154abd99SDavid du Colombier 		return -1;
191154abd99SDavid du Colombier 	}
192154abd99SDavid du Colombier 
193154abd99SDavid du Colombier 	phy->speed = phy->fd = phy->rfc = phy->tfc = 0;
194154abd99SDavid du Colombier 	if(phy->mscr){
195154abd99SDavid du Colombier 		r = mii->mir(mii, phyno, Mssr);
196154abd99SDavid du Colombier 		if((phy->mscr & Mscr1000TFD) && (r & Mssr1000TFD)){
197154abd99SDavid du Colombier 			phy->speed = 1000;
198154abd99SDavid du Colombier 			phy->fd = 1;
199154abd99SDavid du Colombier 		}
200154abd99SDavid du Colombier 		else if((phy->mscr & Mscr1000THD) && (r & Mssr1000THD))
201154abd99SDavid du Colombier 			phy->speed = 1000;
202154abd99SDavid du Colombier 	}
203154abd99SDavid du Colombier 
204154abd99SDavid du Colombier 	anlpar = mii->mir(mii, phyno, Anlpar);
205154abd99SDavid du Colombier 	if(phy->speed == 0){
206154abd99SDavid du Colombier 		r = phy->anar & anlpar;
207154abd99SDavid du Colombier 		if(r & AnaTXFD){
208154abd99SDavid du Colombier 			phy->speed = 100;
209154abd99SDavid du Colombier 			phy->fd = 1;
210154abd99SDavid du Colombier 		}
211154abd99SDavid du Colombier 		else if(r & AnaTXHD)
212154abd99SDavid du Colombier 			phy->speed = 100;
213154abd99SDavid du Colombier 		else if(r & Ana10FD){
214154abd99SDavid du Colombier 			phy->speed = 10;
215154abd99SDavid du Colombier 			phy->fd = 1;
216154abd99SDavid du Colombier 		}
217154abd99SDavid du Colombier 		else if(r & Ana10HD)
218154abd99SDavid du Colombier 			phy->speed = 10;
219154abd99SDavid du Colombier 	}
220154abd99SDavid du Colombier 	if(phy->speed == 0) {
221154abd99SDavid du Colombier 		// print("miistatus: phy speed 0\n");
222154abd99SDavid du Colombier 		return -1;
223154abd99SDavid du Colombier 	}
224154abd99SDavid du Colombier 
225154abd99SDavid du Colombier 	if(phy->fd){
226154abd99SDavid du Colombier 		p = phy->fc;
227154abd99SDavid du Colombier 		r = anlpar & (AnaAP|AnaP);
228154abd99SDavid du Colombier 		if(p == AnaAP && r == (AnaAP|AnaP))
229154abd99SDavid du Colombier 			phy->tfc = 1;
230154abd99SDavid du Colombier 		else if(p == (AnaAP|AnaP) && r == AnaAP)
231154abd99SDavid du Colombier 			phy->rfc = 1;
232154abd99SDavid du Colombier 		else if((p & AnaP) && (r & AnaP))
233154abd99SDavid du Colombier 			phy->rfc = phy->tfc = 1;
234154abd99SDavid du Colombier 	}
235154abd99SDavid du Colombier 
236154abd99SDavid du Colombier 	phy->link = 1;
237154abd99SDavid du Colombier 
238154abd99SDavid du Colombier 	return 0;
239154abd99SDavid du Colombier }
240