9ns: Support rename
[akaros.git] / kern / drivers / net / ethermii.c
1 /* This file is part of the UCB release of Plan 9. It is subject to the license
2  * terms in the LICENSE file found in the top-level directory of this
3  * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
4  * part of the UCB release of Plan 9, including this file, may be copied,
5  * modified, propagated, or distributed except according to the terms contained
6  * in the LICENSE file. */
7
8 #include <slab.h>
9 #include <kmalloc.h>
10 #include <kref.h>
11 #include <string.h>
12 #include <stdio.h>
13 #include <assert.h>
14 #include <error.h>
15 #include <cpio.h>
16 #include <pmap.h>
17 #include <smp.h>
18 #include "ethermii.h"
19
20 static int
21 miiprobe(struct mii* mii, int mask)
22 {
23         struct miiphy *miiphy;
24         int bit, oui, phyno, r, rmask;
25
26         /*
27          * Probe through mii for PHYs in mask;
28          * return the mask of those found in the current probe.
29          * If the PHY has not already been probed, update
30          * the Mii information.
31          */
32         rmask = 0;
33         for(phyno = 0; phyno < NMiiPhy; phyno++){
34                 bit = 1<<phyno;
35                 if(!(mask & bit))
36                         continue;
37                 if(mii->mask & bit){
38                         rmask |= bit;
39                         continue;
40                 }
41                 if(mii->rw(mii, 0, phyno, Bmsr, 0) == -1)
42                         continue;
43                 r = mii->rw(mii, 0, phyno, Phyidr1, 0)<<16;
44                 r |= mii->rw(mii, 0, phyno, Phyidr2, 0);
45                 oui = (r>>10) & 0xffff;
46                 if(oui == 0xffff || oui == 0)
47                         continue;
48
49                 if((miiphy = kzmalloc(sizeof(struct miiphy), 0)) == NULL)
50                         continue;
51
52                 miiphy->mii = mii;
53                 miiphy->phyno = phyno;
54                 miiphy->phyid = r;
55                 miiphy->oui = oui;
56
57                 miiphy->anar = ~0;
58                 miiphy->fc = ~0;
59                 miiphy->mscr = ~0;
60
61                 mii->phy[phyno] = miiphy;
62                 if(mii->curphy == NULL)
63                         mii->curphy = miiphy;
64                 mii->mask |= bit;
65                 mii->nphy++;
66
67                 rmask |= bit;
68         }
69         return rmask;
70 }
71
72 int
73 miimir(struct mii* mii, int r)
74 {
75         if(mii == NULL || mii->ctlr == NULL || mii->curphy == NULL)
76                 return -1;
77         return mii->rw(mii, 0, mii->curphy->phyno, r, 0);
78 }
79
80 int
81 miimiw(struct mii* mii, int r, int data)
82 {
83         if(mii == NULL || mii->ctlr == NULL || mii->curphy == NULL)
84                 return -1;
85         return mii->rw(mii, 1, mii->curphy->phyno, r, data);
86 }
87
88 int
89 miireset(struct mii* mii)
90 {
91         int bmcr, timeo;
92
93         if(mii == NULL || mii->ctlr == NULL || mii->curphy == NULL)
94                 return -1;
95         bmcr = mii->rw(mii, 0, mii->curphy->phyno, Bmcr, 0);
96         mii->rw(mii, 1, mii->curphy->phyno, Bmcr, BmcrR|bmcr);
97         for(timeo = 0; timeo < 1000; timeo++){
98                 bmcr = mii->rw(mii, 0, mii->curphy->phyno, Bmcr, 0);
99                 if(!(bmcr & BmcrR))
100                         break;
101                 udelay(1);
102         }
103         if(bmcr & BmcrR)
104                 return -1;
105         if(bmcr & BmcrI)
106                 mii->rw(mii, 1, mii->curphy->phyno, Bmcr, bmcr & ~BmcrI);
107         return 0;
108 }
109
110 int
111 miiane(struct mii* mii, int a, int p, int e)
112 {
113         int anar, bmsr, mscr, r, phyno;
114
115         if(mii == NULL || mii->ctlr == NULL || mii->curphy == NULL)
116                 return -1;
117         phyno = mii->curphy->phyno;
118
119         mii->rw(mii, 1, phyno, Bmsr, 0);
120         bmsr = mii->rw(mii, 0, phyno, Bmsr, 0);
121         if(!(bmsr & BmsrAna))
122                 return -1;
123
124         if(a != ~0)
125                 anar = (AnaTXFD|AnaTXHD|Ana10FD|Ana10HD) & a;
126         else if(mii->curphy->anar != ~0)
127                 anar = mii->curphy->anar;
128         else{
129                 anar = mii->rw(mii, 0, phyno, Anar, 0);
130                 anar &= ~(AnaAP|AnaP|AnaT4|AnaTXFD|AnaTXHD|Ana10FD|Ana10HD);
131                 if(bmsr & Bmsr10THD)
132                         anar |= Ana10HD;
133                 if(bmsr & Bmsr10TFD)
134                         anar |= Ana10FD;
135                 if(bmsr & Bmsr100TXHD)
136                         anar |= AnaTXHD;
137                 if(bmsr & Bmsr100TXFD)
138                         anar |= AnaTXFD;
139         }
140         mii->curphy->anar = anar;
141
142         if(p != ~0)
143                 anar |= (AnaAP|AnaP) & p;
144         else if(mii->curphy->fc != ~0)
145                 anar |= mii->curphy->fc;
146         mii->curphy->fc = (AnaAP|AnaP) & anar;
147
148         if(bmsr & BmsrEs){
149                 mscr = mii->rw(mii, 0, phyno, Mscr, 0);
150                 mscr &= ~(Mscr1000TFD|Mscr1000THD);
151                 if(e != ~0)
152                         mscr |= (Mscr1000TFD|Mscr1000THD) & e;
153                 else if(mii->curphy->mscr != ~0)
154                         mscr = mii->curphy->mscr;
155                 else{
156                         r = mii->rw(mii, 0, phyno, Esr, 0);
157                         if(r & Esr1000THD)
158                                 mscr |= Mscr1000THD;
159                         if(r & Esr1000TFD)
160                                 mscr |= Mscr1000TFD;
161                 }
162                 mii->curphy->mscr = mscr;
163                 mii->rw(mii, 1, phyno, Mscr, mscr);
164         }
165         else
166                 mii->curphy->mscr = 0;
167         mii->rw(mii, 1, phyno, Anar, anar);
168
169         r = mii->rw(mii, 0, phyno, Bmcr, 0);
170         if(!(r & BmcrR)){
171                 r |= BmcrAne|BmcrRan;
172                 mii->rw(mii, 1, phyno, Bmcr, r);
173         }
174
175         return 0;
176 }
177
178 int
179 miistatus(struct mii* mii)
180 {
181         struct miiphy *phy;
182         int anlpar, bmsr, p, r, phyno;
183
184         if(mii == NULL || mii->ctlr == NULL || mii->curphy == NULL)
185                 return -1;
186         phy = mii->curphy;
187         phyno = phy->phyno;
188
189         /*
190          * Check Auto-Negotiation is complete and link is up.
191          * (Read status twice as the Ls bit is sticky).
192          */
193         bmsr = mii->rw(mii, 0, phyno, Bmsr, 0);
194         if(!(bmsr & (BmsrAnc|BmsrAna)))
195                 return -1;
196
197         bmsr = mii->rw(mii, 0, phyno, Bmsr, 0);
198         if(!(bmsr & BmsrLs)){
199                 phy->link = 0;
200                 return -1;
201         }
202
203         phy->speed = phy->fd = phy->rfc = phy->tfc = 0;
204         if(phy->mscr){
205                 r = mii->rw(mii, 0, phyno, Mssr, 0);
206                 if((phy->mscr & Mscr1000TFD) && (r & Mssr1000TFD)){
207                         phy->speed = 1000;
208                         phy->fd = 1;
209                 }
210                 else if((phy->mscr & Mscr1000THD) && (r & Mssr1000THD))
211                         phy->speed = 1000;
212         }
213
214         anlpar = mii->rw(mii, 0, phyno, Anlpar, 0);
215         if(phy->speed == 0){
216                 r = phy->anar & anlpar;
217                 if(r & AnaTXFD){
218                         phy->speed = 100;
219                         phy->fd = 1;
220                 }
221                 else if(r & AnaTXHD)
222                         phy->speed = 100;
223                 else if(r & Ana10FD){
224                         phy->speed = 10;
225                         phy->fd = 1;
226                 }
227                 else if(r & Ana10HD)
228                         phy->speed = 10;
229         }
230         if(phy->speed == 0)
231                 return -1;
232
233         if(phy->fd){
234                 p = phy->fc;
235                 r = anlpar & (AnaAP|AnaP);
236                 if(p == AnaAP && r == (AnaAP|AnaP))
237                         phy->tfc = 1;
238                 else if(p == (AnaAP|AnaP) && r == AnaAP)
239                         phy->rfc = 1;
240                 else if((p & AnaP) && (r & AnaP))
241                         phy->rfc = phy->tfc = 1;
242         }
243
244         phy->link = 1;
245
246         return 0;
247 }
248
249 char*
250 miidumpphy(struct mii* mii, char* p, char* e)
251 {
252         int i, r;
253
254         if(mii == NULL || mii->curphy == NULL)
255                 return p;
256
257         p = seprintf(p, e, "phy:   ");
258         for(i = 0; i < NMiiPhyr; i++){
259                 if(i && ((i & 0x07) == 0))
260                         p = seprintf(p, e, "\n       ");
261                 r = mii->rw(mii, 0, mii->curphy->phyno, i, 0);
262                 p = seprintf(p, e, " %4.4ux", r);
263         }
264         p = seprintf(p, e, "\n");
265
266         return p;
267 }
268
269 void
270 miidetach(struct mii* mii)
271 {
272         int i;
273
274         for(i = 0; i < NMiiPhy; i++){
275                 if(mii->phy[i] == NULL)
276                         continue;
277                 kfree(mii);
278                 mii->phy[i] = NULL;
279         }
280         kfree(mii);
281 }
282
283 struct mii*
284 miiattach(void* ctlr, int mask, int (*rw)(struct mii*, int unused_int, int, int, int))
285 {
286         struct mii* mii;
287
288         if((mii = kzmalloc(sizeof(struct mii), 0)) == NULL)
289                 return NULL;
290         mii->ctlr = ctlr;
291         mii->rw = rw;
292
293         if(miiprobe(mii, mask) == 0){
294                 kfree(mii);
295                 mii = NULL;
296         }
297
298         return mii;
299 }