mii_physubr.c revision 1.13 1 /* $NetBSD: mii_physubr.c,v 1.13 2000/02/03 05:38:57 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 /*
41 * Subroutines common to all PHYs.
42 */
43
44 #include <sys/param.h>
45 #include <sys/device.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/socket.h>
49 #include <sys/errno.h>
50
51 #include <net/if.h>
52 #include <net/if_media.h>
53
54 #include <dev/mii/mii.h>
55 #include <dev/mii/miivar.h>
56
57 /*
58 * Media to register setting conversion table. Order matters.
59 */
60 const struct mii_media mii_media_table[] = {
61 { BMCR_ISO, ANAR_CSMA }, /* None */
62 { 0, ANAR_CSMA|ANAR_10 }, /* 10baseT */
63 { BMCR_FDX, ANAR_CSMA|ANAR_10_FD }, /* 10baseT-FDX */
64 { BMCR_S100, ANAR_CSMA|ANAR_T4 }, /* 100baseT4 */
65 { BMCR_S100, ANAR_CSMA|ANAR_TX }, /* 100baseTX */
66 { BMCR_S100|BMCR_FDX, ANAR_CSMA|ANAR_TX_FD }, /* 100baseTX-FDX */
67 };
68
69 void mii_phy_auto_timeout __P((void *));
70
71 void
72 mii_phy_setmedia(sc)
73 struct mii_softc *sc;
74 {
75 struct mii_data *mii = sc->mii_pdata;
76 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
77 int bmcr, anar;
78
79 if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
80 (void) mii_phy_auto(sc, 1);
81 return;
82 }
83
84 /*
85 * Table index is stored in the media entry.
86 */
87
88 #ifdef DIAGNOSTIC
89 if (ife->ifm_data < 0 || ife->ifm_data >= MII_NMEDIA)
90 panic("mii_phy_setmedia");
91 #endif
92
93 anar = mii_media_table[ife->ifm_data].mm_anar;
94 bmcr = mii_media_table[ife->ifm_data].mm_bmcr;
95
96 if (ife->ifm_media & IFM_LOOP)
97 bmcr |= BMCR_LOOP;
98
99 PHY_WRITE(sc, MII_ANAR, anar);
100 PHY_WRITE(sc, MII_BMCR, bmcr);
101 }
102
103 int
104 mii_phy_auto(sc, waitfor)
105 struct mii_softc *sc;
106 int waitfor;
107 {
108 int bmsr, i;
109
110 if ((sc->mii_flags & MIIF_DOINGAUTO) == 0) {
111 PHY_WRITE(sc, MII_ANAR,
112 BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA);
113 PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
114 }
115
116 if (waitfor) {
117 /* Wait 500ms for it to complete. */
118 for (i = 0; i < 500; i++) {
119 if ((bmsr = PHY_READ(sc, MII_BMSR)) & BMSR_ACOMP)
120 return (0);
121 delay(1000);
122 }
123
124 /*
125 * Don't need to worry about clearing MIIF_DOINGAUTO.
126 * If that's set, a timeout is pending, and it will
127 * clear the flag.
128 */
129 return (EIO);
130 }
131
132 /*
133 * Just let it finish asynchronously. This is for the benefit of
134 * the tick handler driving autonegotiation. Don't want 500ms
135 * delays all the time while the system is running!
136 */
137 if ((sc->mii_flags & MIIF_DOINGAUTO) == 0) {
138 sc->mii_flags |= MIIF_DOINGAUTO;
139 timeout(mii_phy_auto_timeout, sc, hz >> 1);
140 }
141 return (EJUSTRETURN);
142 }
143
144 void
145 mii_phy_auto_timeout(arg)
146 void *arg;
147 {
148 struct mii_softc *sc = arg;
149 int s, bmsr;
150
151 if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0)
152 return;
153
154 s = splnet();
155 sc->mii_flags &= ~MIIF_DOINGAUTO;
156 bmsr = PHY_READ(sc, MII_BMSR);
157
158 /* Update the media status. */
159 (void) (*sc->mii_service)(sc, sc->mii_pdata, MII_POLLSTAT);
160 splx(s);
161 }
162
163 void
164 mii_phy_reset(sc)
165 struct mii_softc *sc;
166 {
167 int reg, i;
168
169 if (sc->mii_flags & MIIF_NOISOLATE)
170 reg = BMCR_RESET;
171 else
172 reg = BMCR_RESET | BMCR_ISO;
173 PHY_WRITE(sc, MII_BMCR, reg);
174
175 /* Wait 100ms for it to complete. */
176 for (i = 0; i < 100; i++) {
177 reg = PHY_READ(sc, MII_BMCR);
178 if ((reg & BMCR_RESET) == 0)
179 break;
180 delay(1000);
181 }
182
183 if (sc->mii_inst != 0 && ((sc->mii_flags & MIIF_NOISOLATE) == 0))
184 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
185 }
186
187 void
188 mii_phy_down(sc)
189 struct mii_softc *sc;
190 {
191
192 if (sc->mii_flags & MIIF_DOINGAUTO) {
193 sc->mii_flags &= ~MIIF_DOINGAUTO;
194 untimeout(mii_phy_auto_timeout, sc);
195 }
196 }
197
198 void
199 mii_phy_status(sc)
200 struct mii_softc *sc;
201 {
202
203 (*sc->mii_status)(sc);
204 }
205
206 /*
207 * Initialize generic PHY media based on BMSR, called when a PHY is
208 * attached. We expect to be set up to print a comma-separated list
209 * of media names. Does not print a newline.
210 */
211 void
212 mii_phy_add_media(sc)
213 struct mii_softc *sc;
214 {
215 struct mii_data *mii = sc->mii_pdata;
216 const char *sep = "";
217
218 #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
219 #define PRINT(s) printf("%s%s", sep, s); sep = ", "
220
221 if ((sc->mii_flags & MIIF_NOISOLATE) == 0)
222 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
223 MII_MEDIA_NONE);
224
225 if (sc->mii_capabilities & BMSR_10THDX) {
226 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst),
227 MII_MEDIA_10_T);
228 #if 0
229 if ((sc->mii_flags & MIIF_NOLOOP) == 0)
230 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_LOOP,
231 sc->mii_inst), MII_MEDIA_10_T);
232 #endif
233 PRINT("10baseT");
234 }
235 if (sc->mii_capabilities & BMSR_10TFDX) {
236 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst),
237 MII_MEDIA_10_T_FDX);
238 PRINT("10baseT-FDX");
239 }
240 if (sc->mii_capabilities & BMSR_100TXHDX) {
241 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst),
242 MII_MEDIA_100_TX);
243 #if 0
244 if ((sc->mii_flags & MIIF_NOLOOP) == 0)
245 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP,
246 sc->mii_inst), MII_MEDIA_100_TX);
247 #endif
248 PRINT("100baseTX");
249 }
250 if (sc->mii_capabilities & BMSR_100TXFDX) {
251 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst),
252 MII_MEDIA_100_TX_FDX);
253 PRINT("100baseTX-FDX");
254 }
255 if (sc->mii_capabilities & BMSR_100T4) {
256 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, 0, sc->mii_inst),
257 MII_MEDIA_100_T4);
258 #if 0
259 if ((sc->mii_flags & MIIF_NOLOOP) == 0)
260 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, IFM_LOOP,
261 sc->mii_inst), MII_MEDIA_100_T4);
262 #endif
263 PRINT("100baseT4");
264 }
265 if (sc->mii_capabilities & BMSR_ANEG) {
266 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst),
267 MII_NMEDIA); /* intentionally invalid index */
268 PRINT("auto");
269 }
270 #undef ADD
271 #undef PRINT
272 }
273
274 void
275 mii_phy_delete_media(sc)
276 struct mii_softc *sc;
277 {
278 struct mii_data *mii = sc->mii_pdata;
279
280 ifmedia_delete_instance(&mii->mii_media, sc->mii_inst);
281 }
282
283 int
284 mii_phy_activate(self, act)
285 struct device *self;
286 enum devact act;
287 {
288 int rv = 0;
289
290 switch (act) {
291 case DVACT_ACTIVATE:
292 rv = EOPNOTSUPP;
293 break;
294
295 case DVACT_DEACTIVATE:
296 /* Nothing special to do. */
297 break;
298 }
299
300 return (rv);
301 }
302
303 int
304 mii_phy_detach(self, flags)
305 struct device *self;
306 int flags;
307 {
308 struct mii_softc *sc = (void *) self;
309
310 if (sc->mii_flags & MIIF_DOINGAUTO)
311 untimeout(mii_phy_auto_timeout, sc);
312
313 mii_phy_delete_media(sc);
314
315 return (0);
316 }
317