xref: /plan9/sys/src/9/pc/ethermii.c (revision df13bbe8b06a55bf46c4d90459815d1fba9e1a13)
1e5fc48fbSDavid du Colombier #include "u.h"
2e5fc48fbSDavid du Colombier #include "../port/lib.h"
3e5fc48fbSDavid du Colombier #include "mem.h"
4e5fc48fbSDavid du Colombier #include "dat.h"
5e5fc48fbSDavid du Colombier #include "fns.h"
6e5fc48fbSDavid du Colombier #include "io.h"
7e5fc48fbSDavid du Colombier #include "../port/error.h"
8e5fc48fbSDavid du Colombier #include "../port/netif.h"
9e5fc48fbSDavid du Colombier 
10e5fc48fbSDavid du Colombier #include "etherif.h"
11e5fc48fbSDavid du Colombier #include "ethermii.h"
12e5fc48fbSDavid du Colombier 
13e5fc48fbSDavid du Colombier int
mii(Mii * mii,int mask)14e5fc48fbSDavid du Colombier mii(Mii* mii, int mask)
15e5fc48fbSDavid du Colombier {
16e5fc48fbSDavid du Colombier 	MiiPhy *miiphy;
1751711cb6SDavid du Colombier 	int bit, oui, phyno, r, rmask;
18e5fc48fbSDavid du Colombier 
19e5fc48fbSDavid du Colombier 	/*
20e5fc48fbSDavid du Colombier 	 * Probe through mii for PHYs in mask;
21e5fc48fbSDavid du Colombier 	 * return the mask of those found in the current probe.
22e5fc48fbSDavid du Colombier 	 * If the PHY has not already been probed, update
23e5fc48fbSDavid du Colombier 	 * the Mii information.
24e5fc48fbSDavid du Colombier 	 */
25e5fc48fbSDavid du Colombier 	rmask = 0;
26e5fc48fbSDavid du Colombier 	for(phyno = 0; phyno < NMiiPhy; phyno++){
27e5fc48fbSDavid du Colombier 		bit = 1<<phyno;
28e5fc48fbSDavid du Colombier 		if(!(mask & bit))
29e5fc48fbSDavid du Colombier 			continue;
30e5fc48fbSDavid du Colombier 		if(mii->mask & bit){
31e5fc48fbSDavid du Colombier 			rmask |= bit;
32e5fc48fbSDavid du Colombier 			continue;
33e5fc48fbSDavid du Colombier 		}
34e5fc48fbSDavid du Colombier 		if(mii->mir(mii, phyno, Bmsr) == -1)
35e5fc48fbSDavid du Colombier 			continue;
3651711cb6SDavid du Colombier 		r = mii->mir(mii, phyno, Phyidr1);
3751711cb6SDavid du Colombier 		oui = (r & 0x3FFF)<<6;
3851711cb6SDavid du Colombier 		r = mii->mir(mii, phyno, Phyidr2);
3951711cb6SDavid du Colombier 		oui |= r>>10;
4051711cb6SDavid du Colombier 		if(oui == 0xFFFFF || oui == 0)
4151711cb6SDavid du Colombier 			continue;
4251711cb6SDavid du Colombier 
43e5fc48fbSDavid du Colombier 		if((miiphy = malloc(sizeof(MiiPhy))) == nil)
44e5fc48fbSDavid du Colombier 			continue;
45e5fc48fbSDavid du Colombier 
46e5fc48fbSDavid du Colombier 		miiphy->mii = mii;
4751711cb6SDavid du Colombier 		miiphy->oui = oui;
48e5fc48fbSDavid du Colombier 		miiphy->phyno = phyno;
49e5fc48fbSDavid du Colombier 
50e5fc48fbSDavid du Colombier 		miiphy->anar = ~0;
51e5fc48fbSDavid du Colombier 		miiphy->fc = ~0;
52e5fc48fbSDavid du Colombier 		miiphy->mscr = ~0;
53e5fc48fbSDavid du Colombier 
54e5fc48fbSDavid du Colombier 		mii->phy[phyno] = miiphy;
55e5fc48fbSDavid du Colombier 		if(mii->curphy == nil)
56e5fc48fbSDavid du Colombier 			mii->curphy = miiphy;
57e5fc48fbSDavid du Colombier 		mii->mask |= bit;
58e5fc48fbSDavid du Colombier 		mii->nphy++;
59e5fc48fbSDavid du Colombier 
60e5fc48fbSDavid du Colombier 		rmask |= bit;
61e5fc48fbSDavid du Colombier 	}
62e5fc48fbSDavid du Colombier 	return rmask;
63e5fc48fbSDavid du Colombier }
64e5fc48fbSDavid du Colombier 
65e5fc48fbSDavid du Colombier int
miimir(Mii * mii,int r)66e5fc48fbSDavid du Colombier miimir(Mii* mii, int r)
67e5fc48fbSDavid du Colombier {
68e5fc48fbSDavid du Colombier 	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
69e5fc48fbSDavid du Colombier 		return -1;
70e5fc48fbSDavid du Colombier 	return mii->mir(mii, mii->curphy->phyno, r);
71e5fc48fbSDavid du Colombier }
72e5fc48fbSDavid du Colombier 
73e5fc48fbSDavid du Colombier int
miimiw(Mii * mii,int r,int data)74e5fc48fbSDavid du Colombier miimiw(Mii* mii, int r, int data)
75e5fc48fbSDavid du Colombier {
76e5fc48fbSDavid du Colombier 	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
77e5fc48fbSDavid du Colombier 		return -1;
78e5fc48fbSDavid du Colombier 	return mii->miw(mii, mii->curphy->phyno, r, data);
79e5fc48fbSDavid du Colombier }
80e5fc48fbSDavid du Colombier 
81e5fc48fbSDavid du Colombier int
miireset(Mii * mii)82e5fc48fbSDavid du Colombier miireset(Mii* mii)
83e5fc48fbSDavid du Colombier {
84e5fc48fbSDavid du Colombier 	int bmcr;
85e5fc48fbSDavid du Colombier 
86e5fc48fbSDavid du Colombier 	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
87e5fc48fbSDavid du Colombier 		return -1;
88e5fc48fbSDavid du Colombier 	bmcr = mii->mir(mii, mii->curphy->phyno, Bmcr);
89e5fc48fbSDavid du Colombier 	bmcr |= BmcrR;
90e5fc48fbSDavid du Colombier 	mii->miw(mii, mii->curphy->phyno, Bmcr, bmcr);
91e5fc48fbSDavid du Colombier 	microdelay(1);
92e5fc48fbSDavid du Colombier 
93e5fc48fbSDavid du Colombier 	return 0;
94e5fc48fbSDavid du Colombier }
95e5fc48fbSDavid du Colombier 
96e5fc48fbSDavid du Colombier int
miiane(Mii * mii,int a,int p,int e)97e5fc48fbSDavid du Colombier miiane(Mii* mii, int a, int p, int e)
98e5fc48fbSDavid du Colombier {
99e5fc48fbSDavid du Colombier 	int anar, bmsr, mscr, r, phyno;
100e5fc48fbSDavid du Colombier 
101e5fc48fbSDavid du Colombier 	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
102e5fc48fbSDavid du Colombier 		return -1;
103e5fc48fbSDavid du Colombier 	phyno = mii->curphy->phyno;
104e5fc48fbSDavid du Colombier 
105e5fc48fbSDavid du Colombier 	bmsr = mii->mir(mii, phyno, Bmsr);
106e5fc48fbSDavid du Colombier 	if(!(bmsr & BmsrAna))
107e5fc48fbSDavid du Colombier 		return -1;
108e5fc48fbSDavid du Colombier 
109e5fc48fbSDavid du Colombier 	if(a != ~0)
110e5fc48fbSDavid du Colombier 		anar = (AnaTXFD|AnaTXHD|Ana10FD|Ana10HD) & a;
111e5fc48fbSDavid du Colombier 	else if(mii->curphy->anar != ~0)
112e5fc48fbSDavid du Colombier 		anar = mii->curphy->anar;
113e5fc48fbSDavid du Colombier 	else{
114e5fc48fbSDavid du Colombier 		anar = mii->mir(mii, phyno, Anar);
115e5fc48fbSDavid du Colombier 		anar &= ~(AnaAP|AnaP|AnaT4|AnaTXFD|AnaTXHD|Ana10FD|Ana10HD);
116e5fc48fbSDavid du Colombier 		if(bmsr & Bmsr10THD)
117e5fc48fbSDavid du Colombier 			anar |= Ana10HD;
118e5fc48fbSDavid du Colombier 		if(bmsr & Bmsr10TFD)
119e5fc48fbSDavid du Colombier 			anar |= Ana10FD;
120e5fc48fbSDavid du Colombier 		if(bmsr & Bmsr100TXHD)
121e5fc48fbSDavid du Colombier 			anar |= AnaTXHD;
122e5fc48fbSDavid du Colombier 		if(bmsr & Bmsr100TXFD)
123e5fc48fbSDavid du Colombier 			anar |= AnaTXFD;
124e5fc48fbSDavid du Colombier 	}
125e5fc48fbSDavid du Colombier 	mii->curphy->anar = anar;
126e5fc48fbSDavid du Colombier 
127e5fc48fbSDavid du Colombier 	if(p != ~0)
128e5fc48fbSDavid du Colombier 		anar |= (AnaAP|AnaP) & p;
129e5fc48fbSDavid du Colombier 	else if(mii->curphy->fc != ~0)
130e5fc48fbSDavid du Colombier 		anar |= mii->curphy->fc;
131e5fc48fbSDavid du Colombier 	mii->curphy->fc = (AnaAP|AnaP) & anar;
132e5fc48fbSDavid du Colombier 
133e5fc48fbSDavid du Colombier 	if(bmsr & BmsrEs){
134e5fc48fbSDavid du Colombier 		mscr = mii->mir(mii, phyno, Mscr);
135e5fc48fbSDavid du Colombier 		mscr &= ~(Mscr1000TFD|Mscr1000THD);
136e5fc48fbSDavid du Colombier 		if(e != ~0)
137e5fc48fbSDavid du Colombier 			mscr |= (Mscr1000TFD|Mscr1000THD) & e;
138e5fc48fbSDavid du Colombier 		else if(mii->curphy->mscr != ~0)
139e5fc48fbSDavid du Colombier 			mscr = mii->curphy->mscr;
140e5fc48fbSDavid du Colombier 		else{
141e5fc48fbSDavid du Colombier 			r = mii->mir(mii, phyno, Esr);
142e5fc48fbSDavid du Colombier 			if(r & Esr1000THD)
143e5fc48fbSDavid du Colombier 				mscr |= Mscr1000THD;
144e5fc48fbSDavid du Colombier 			if(r & Esr1000TFD)
145e5fc48fbSDavid du Colombier 				mscr |= Mscr1000TFD;
146e5fc48fbSDavid du Colombier 		}
147e5fc48fbSDavid du Colombier 		mii->curphy->mscr = mscr;
148e5fc48fbSDavid du Colombier 		mii->miw(mii, phyno, Mscr, mscr);
149e5fc48fbSDavid du Colombier 	}
150e5fc48fbSDavid du Colombier 	mii->miw(mii, phyno, Anar, anar);
151e5fc48fbSDavid du Colombier 
152e5fc48fbSDavid du Colombier 	r = mii->mir(mii, phyno, Bmcr);
153e5fc48fbSDavid du Colombier 	if(!(r & BmcrR)){
154e5fc48fbSDavid du Colombier 		r |= BmcrAne|BmcrRan;
155e5fc48fbSDavid du Colombier 		mii->miw(mii, phyno, Bmcr, r);
156e5fc48fbSDavid du Colombier 	}
157e5fc48fbSDavid du Colombier 
158e5fc48fbSDavid du Colombier 	return 0;
159e5fc48fbSDavid du Colombier }
160e5fc48fbSDavid du Colombier 
161e5fc48fbSDavid du Colombier int
miistatus(Mii * mii)162e5fc48fbSDavid du Colombier miistatus(Mii* mii)
163e5fc48fbSDavid du Colombier {
164e5fc48fbSDavid du Colombier 	MiiPhy *phy;
165e5fc48fbSDavid du Colombier 	int anlpar, bmsr, p, r, phyno;
166e5fc48fbSDavid du Colombier 
167e5fc48fbSDavid du Colombier 	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
168e5fc48fbSDavid du Colombier 		return -1;
169e5fc48fbSDavid du Colombier 	phy = mii->curphy;
170e5fc48fbSDavid du Colombier 	phyno = phy->phyno;
171e5fc48fbSDavid du Colombier 
172e5fc48fbSDavid du Colombier 	/*
173e5fc48fbSDavid du Colombier 	 * Check Auto-Negotiation is complete and link is up.
174e5fc48fbSDavid du Colombier 	 * (Read status twice as the Ls bit is sticky).
175e5fc48fbSDavid du Colombier 	 */
176e5fc48fbSDavid du Colombier 	bmsr = mii->mir(mii, phyno, Bmsr);
177*df13bbe8SDavid du Colombier 	if(!(bmsr & (BmsrAnc|BmsrAna))) {
178*df13bbe8SDavid du Colombier 		// print("miistatus: auto-neg incomplete\n");
179e5fc48fbSDavid du Colombier 		return -1;
180e5fc48fbSDavid du Colombier 	}
181e5fc48fbSDavid du Colombier 
182e5fc48fbSDavid du Colombier 	bmsr = mii->mir(mii, phyno, Bmsr);
183e5fc48fbSDavid du Colombier 	if(!(bmsr & BmsrLs)){
184*df13bbe8SDavid du Colombier 		// print("miistatus: link down\n");
185e5fc48fbSDavid du Colombier 		phy->link = 0;
186e5fc48fbSDavid du Colombier 		return -1;
187e5fc48fbSDavid du Colombier 	}
188e5fc48fbSDavid du Colombier 
189e5fc48fbSDavid du Colombier 	phy->speed = phy->fd = phy->rfc = phy->tfc = 0;
190e5fc48fbSDavid du Colombier 	if(phy->mscr){
191e5fc48fbSDavid du Colombier 		r = mii->mir(mii, phyno, Mssr);
192e5fc48fbSDavid du Colombier 		if((phy->mscr & Mscr1000TFD) && (r & Mssr1000TFD)){
193e5fc48fbSDavid du Colombier 			phy->speed = 1000;
194e5fc48fbSDavid du Colombier 			phy->fd = 1;
195e5fc48fbSDavid du Colombier 		}
196e5fc48fbSDavid du Colombier 		else if((phy->mscr & Mscr1000THD) && (r & Mssr1000THD))
197e5fc48fbSDavid du Colombier 			phy->speed = 1000;
198e5fc48fbSDavid du Colombier 	}
199e5fc48fbSDavid du Colombier 
200e5fc48fbSDavid du Colombier 	anlpar = mii->mir(mii, phyno, Anlpar);
201e5fc48fbSDavid du Colombier 	if(phy->speed == 0){
202e5fc48fbSDavid du Colombier 		r = phy->anar & anlpar;
203e5fc48fbSDavid du Colombier 		if(r & AnaTXFD){
204e5fc48fbSDavid du Colombier 			phy->speed = 100;
205e5fc48fbSDavid du Colombier 			phy->fd = 1;
206e5fc48fbSDavid du Colombier 		}
207e5fc48fbSDavid du Colombier 		else if(r & AnaTXHD)
208e5fc48fbSDavid du Colombier 			phy->speed = 100;
209e5fc48fbSDavid du Colombier 		else if(r & Ana10FD){
210e5fc48fbSDavid du Colombier 			phy->speed = 10;
211e5fc48fbSDavid du Colombier 			phy->fd = 1;
212e5fc48fbSDavid du Colombier 		}
213e5fc48fbSDavid du Colombier 		else if(r & Ana10HD)
214e5fc48fbSDavid du Colombier 			phy->speed = 10;
215e5fc48fbSDavid du Colombier 	}
216*df13bbe8SDavid du Colombier 	if(phy->speed == 0) {
217*df13bbe8SDavid du Colombier 		// print("miistatus: phy speed 0\n");
218e5fc48fbSDavid du Colombier 		return -1;
219e5fc48fbSDavid du Colombier 	}
220e5fc48fbSDavid du Colombier 
221e5fc48fbSDavid du Colombier 	if(phy->fd){
222e5fc48fbSDavid du Colombier 		p = phy->fc;
223e5fc48fbSDavid du Colombier 		r = anlpar & (AnaAP|AnaP);
224e5fc48fbSDavid du Colombier 		if(p == AnaAP && r == (AnaAP|AnaP))
225e5fc48fbSDavid du Colombier 			phy->tfc = 1;
226e5fc48fbSDavid du Colombier 		else if(p == (AnaAP|AnaP) && r == AnaAP)
227e5fc48fbSDavid du Colombier 			phy->rfc = 1;
228e5fc48fbSDavid du Colombier 		else if((p & AnaP) && (r & AnaP))
229e5fc48fbSDavid du Colombier 			phy->rfc = phy->tfc = 1;
230e5fc48fbSDavid du Colombier 	}
231e5fc48fbSDavid du Colombier 
232e5fc48fbSDavid du Colombier 	phy->link = 1;
233e5fc48fbSDavid du Colombier 
234e5fc48fbSDavid du Colombier 	return 0;
235e5fc48fbSDavid du Colombier }
236