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