kconfig: use pkg-config for ncurses detection
[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 <assert.h>
9 #include <cpio.h>
10 #include <error.h>
11 #include <kmalloc.h>
12 #include <kref.h>
13 #include <pmap.h>
14 #include <slab.h>
15 #include <smp.h>
16 #include <stdio.h>
17 #include <string.h>
18
19 #include "ethermii.h"
20
21 static int 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 miimir(struct mii *mii, int r)
73 {
74         if (mii == NULL || mii->ctlr == NULL || mii->curphy == NULL)
75                 return -1;
76         return mii->rw(mii, 0, mii->curphy->phyno, r, 0);
77 }
78
79 int miimiw(struct mii *mii, int r, int data)
80 {
81         if (mii == NULL || mii->ctlr == NULL || mii->curphy == NULL)
82                 return -1;
83         return mii->rw(mii, 1, mii->curphy->phyno, r, data);
84 }
85
86 int miireset(struct mii *mii)
87 {
88         int bmcr, timeo;
89
90         if (mii == NULL || mii->ctlr == NULL || mii->curphy == NULL)
91                 return -1;
92         bmcr = mii->rw(mii, 0, mii->curphy->phyno, Bmcr, 0);
93         mii->rw(mii, 1, mii->curphy->phyno, Bmcr, BmcrR | bmcr);
94         for (timeo = 0; timeo < 1000; timeo++) {
95                 bmcr = mii->rw(mii, 0, mii->curphy->phyno, Bmcr, 0);
96                 if (!(bmcr & BmcrR))
97                         break;
98                 udelay(1);
99         }
100         if (bmcr & BmcrR)
101                 return -1;
102         if (bmcr & BmcrI)
103                 mii->rw(mii, 1, mii->curphy->phyno, Bmcr, bmcr & ~BmcrI);
104         return 0;
105 }
106
107 int miiane(struct mii *mii, int a, int p, int e)
108 {
109         int anar, bmsr, mscr, r, phyno;
110
111         if (mii == NULL || mii->ctlr == NULL || mii->curphy == NULL)
112                 return -1;
113         phyno = mii->curphy->phyno;
114
115         mii->rw(mii, 1, phyno, Bmsr, 0);
116         bmsr = mii->rw(mii, 0, phyno, Bmsr, 0);
117         if (!(bmsr & BmsrAna))
118                 return -1;
119
120         if (a != ~0)
121                 anar = (AnaTXFD | AnaTXHD | Ana10FD | Ana10HD) & a;
122         else if (mii->curphy->anar != ~0)
123                 anar = mii->curphy->anar;
124         else {
125                 anar = mii->rw(mii, 0, phyno, Anar, 0);
126                 anar &= ~(AnaAP | AnaP | AnaT4 | AnaTXFD | AnaTXHD | Ana10FD |
127                           Ana10HD);
128                 if (bmsr & Bmsr10THD)
129                         anar |= Ana10HD;
130                 if (bmsr & Bmsr10TFD)
131                         anar |= Ana10FD;
132                 if (bmsr & Bmsr100TXHD)
133                         anar |= AnaTXHD;
134                 if (bmsr & Bmsr100TXFD)
135                         anar |= AnaTXFD;
136         }
137         mii->curphy->anar = anar;
138
139         if (p != ~0)
140                 anar |= (AnaAP | AnaP) & p;
141         else if (mii->curphy->fc != ~0)
142                 anar |= mii->curphy->fc;
143         mii->curphy->fc = (AnaAP | AnaP) & anar;
144
145         if (bmsr & BmsrEs) {
146                 mscr = mii->rw(mii, 0, phyno, Mscr, 0);
147                 mscr &= ~(Mscr1000TFD | Mscr1000THD);
148                 if (e != ~0)
149                         mscr |= (Mscr1000TFD | Mscr1000THD) & e;
150                 else if (mii->curphy->mscr != ~0)
151                         mscr = mii->curphy->mscr;
152                 else {
153                         r = mii->rw(mii, 0, phyno, Esr, 0);
154                         if (r & Esr1000THD)
155                                 mscr |= Mscr1000THD;
156                         if (r & Esr1000TFD)
157                                 mscr |= Mscr1000TFD;
158                 }
159                 mii->curphy->mscr = mscr;
160                 mii->rw(mii, 1, phyno, Mscr, mscr);
161         } else
162                 mii->curphy->mscr = 0;
163         mii->rw(mii, 1, phyno, Anar, anar);
164
165         r = mii->rw(mii, 0, phyno, Bmcr, 0);
166         if (!(r & BmcrR)) {
167                 r |= BmcrAne | BmcrRan;
168                 mii->rw(mii, 1, phyno, Bmcr, r);
169         }
170
171         return 0;
172 }
173
174 int miistatus(struct mii *mii)
175 {
176         struct miiphy *phy;
177         int anlpar, bmsr, p, r, phyno;
178
179         if (mii == NULL || mii->ctlr == NULL || mii->curphy == NULL)
180                 return -1;
181         phy = mii->curphy;
182         phyno = phy->phyno;
183
184         /*
185          * Check Auto-Negotiation is complete and link is up.
186          * (Read status twice as the Ls bit is sticky).
187          */
188         bmsr = mii->rw(mii, 0, phyno, Bmsr, 0);
189         if (!(bmsr & (BmsrAnc | BmsrAna)))
190                 return -1;
191
192         bmsr = mii->rw(mii, 0, phyno, Bmsr, 0);
193         if (!(bmsr & BmsrLs)) {
194                 phy->link = 0;
195                 return -1;
196         }
197
198         phy->speed = phy->fd = phy->rfc = phy->tfc = 0;
199         if (phy->mscr) {
200                 r = mii->rw(mii, 0, phyno, Mssr, 0);
201                 if ((phy->mscr & Mscr1000TFD) && (r & Mssr1000TFD)) {
202                         phy->speed = 1000;
203                         phy->fd = 1;
204                 } else if ((phy->mscr & Mscr1000THD) && (r & Mssr1000THD))
205                         phy->speed = 1000;
206         }
207
208         anlpar = mii->rw(mii, 0, phyno, Anlpar, 0);
209         if (phy->speed == 0) {
210                 r = phy->anar & anlpar;
211                 if (r & AnaTXFD) {
212                         phy->speed = 100;
213                         phy->fd = 1;
214                 } else if (r & AnaTXHD)
215                         phy->speed = 100;
216                 else if (r & Ana10FD) {
217                         phy->speed = 10;
218                         phy->fd = 1;
219                 } else if (r & Ana10HD)
220                         phy->speed = 10;
221         }
222         if (phy->speed == 0)
223                 return -1;
224
225         if (phy->fd) {
226                 p = phy->fc;
227                 r = anlpar & (AnaAP | AnaP);
228                 if (p == AnaAP && r == (AnaAP | AnaP))
229                         phy->tfc = 1;
230                 else if (p == (AnaAP | AnaP) && r == AnaAP)
231                         phy->rfc = 1;
232                 else if ((p & AnaP) && (r & AnaP))
233                         phy->rfc = phy->tfc = 1;
234         }
235
236         phy->link = 1;
237
238         return 0;
239 }
240
241 char *miidumpphy(struct mii *mii, char *p, char *e)
242 {
243         int i, r;
244
245         if (mii == NULL || mii->curphy == NULL)
246                 return p;
247
248         p = seprintf(p, e, "phy:   ");
249         for (i = 0; i < NMiiPhyr; i++) {
250                 if (i && ((i & 0x07) == 0))
251                         p = seprintf(p, e, "\n       ");
252                 r = mii->rw(mii, 0, mii->curphy->phyno, i, 0);
253                 p = seprintf(p, e, " %4.4ux", r);
254         }
255         p = seprintf(p, e, "\n");
256
257         return p;
258 }
259
260 void miidetach(struct mii *mii)
261 {
262         int i;
263
264         for (i = 0; i < NMiiPhy; i++) {
265                 if (mii->phy[i] == NULL)
266                         continue;
267                 kfree(mii);
268                 mii->phy[i] = NULL;
269         }
270         kfree(mii);
271 }
272
273 struct mii *miiattach(void *ctlr, int mask,
274                       int (*rw)(struct mii *, int unused_int, int, int, int))
275 {
276         struct mii *mii;
277
278         if ((mii = kzmalloc(sizeof(struct mii), 0)) == NULL)
279                 return NULL;
280         mii->ctlr = ctlr;
281         mii->rw = rw;
282
283         if (miiprobe(mii, mask) == 0) {
284                 kfree(mii);
285                 mii = NULL;
286         }
287
288         return mii;
289 }