File: | dev/mii/mii_physubr.c |
Warning: | line 182, column 9 Although the value stored to 'bmsr' is used in the enclosing expression, the value is never actually read from 'bmsr' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: mii_physubr.c,v 1.46 2020/01/15 00:14:47 cheloha Exp $ */ |
2 | /* $NetBSD: mii_physubr.c,v 1.20 2001/04/13 23:30:09 thorpej Exp $ */ |
3 | |
4 | /*- |
5 | * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc. |
6 | * All rights reserved. |
7 | * |
8 | * This code is derived from software contributed to The NetBSD Foundation |
9 | * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, |
10 | * NASA Ames Research Center. |
11 | * |
12 | * Redistribution and use in source and binary forms, with or without |
13 | * modification, are permitted provided that the following conditions |
14 | * are met: |
15 | * 1. Redistributions of source code must retain the above copyright |
16 | * notice, this list of conditions and the following disclaimer. |
17 | * 2. Redistributions in binary form must reproduce the above copyright |
18 | * notice, this list of conditions and the following disclaimer in the |
19 | * documentation and/or other materials provided with the distribution. |
20 | * |
21 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
22 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
23 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
24 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
31 | * POSSIBILITY OF SUCH DAMAGE. |
32 | */ |
33 | |
34 | /* |
35 | * Subroutines common to all PHYs. |
36 | */ |
37 | |
38 | #include <sys/param.h> |
39 | #include <sys/device.h> |
40 | #include <sys/systm.h> |
41 | #include <sys/kernel.h> |
42 | #include <sys/socket.h> |
43 | #include <sys/errno.h> |
44 | |
45 | #include <net/if.h> |
46 | #include <net/if_var.h> |
47 | #include <net/if_media.h> |
48 | |
49 | #include <dev/mii/mii.h> |
50 | #include <dev/mii/miivar.h> |
51 | |
52 | /* |
53 | * Media to register setting conversion table. Order matters. |
54 | * XXX 802.3 doesn't specify ANAR or ANLPAR bits for 1000base. |
55 | */ |
56 | const struct mii_media mii_media_table[] = { |
57 | /* None */ |
58 | { BMCR_ISO0x0400, ANAR_CSMA0x0001, 0 }, |
59 | /* 10baseT */ |
60 | { BMCR_S100x0000, ANAR_CSMA0x0001|ANAR_100x0020, 0 }, |
61 | /* 10baseT-FDX */ |
62 | { BMCR_S100x0000|BMCR_FDX0x0100, ANAR_CSMA0x0001|ANAR_10_FD0x0040, 0 }, |
63 | /* 100baseT4 */ |
64 | { BMCR_S1000x2000, ANAR_CSMA0x0001|ANAR_T40x0200, 0 }, |
65 | /* 100baseTX */ |
66 | { BMCR_S1000x2000, ANAR_CSMA0x0001|ANAR_TX0x0080, 0 }, |
67 | /* 100baseTX-FDX */ |
68 | { BMCR_S1000x2000|BMCR_FDX0x0100, ANAR_CSMA0x0001|ANAR_TX_FD0x0100, 0 }, |
69 | /* 1000baseX */ |
70 | { BMCR_S10000x0040, ANAR_CSMA0x0001, 0 }, |
71 | /* 1000baseX-FDX */ |
72 | { BMCR_S10000x0040|BMCR_FDX0x0100, ANAR_CSMA0x0001, 0 }, |
73 | /* 1000baseT */ |
74 | { BMCR_S10000x0040, ANAR_CSMA0x0001, GTCR_ADV_1000THDX0x0100 }, |
75 | /* 1000baseT-FDX */ |
76 | { BMCR_S10000x0040|BMCR_FDX0x0100, ANAR_CSMA0x0001, GTCR_ADV_1000TFDX0x0200 }, |
77 | }; |
78 | |
79 | void |
80 | mii_phy_setmedia(struct mii_softc *sc) |
81 | { |
82 | struct mii_data *mii = sc->mii_pdata; |
83 | struct ifmedia_entry *ife = mii->mii_media.ifm_cur; |
84 | int bmcr, anar, gtcr; |
85 | |
86 | if (IFM_SUBTYPE(ife->ifm_media)((ife->ifm_media) & 0x00000000000000ffULL) == IFM_AUTO0ULL) { |
87 | if ((PHY_READ(sc, MII_BMCR)(*(sc)->mii_pdata->mii_readreg)((sc)->mii_dev.dv_parent , (sc)->mii_phy, (0x00)) & BMCR_AUTOEN0x1000) == 0 || |
88 | (sc->mii_flags & MIIF_FORCEANEG0x0400)) |
89 | (void) mii_phy_auto(sc, 1); |
90 | return; |
91 | } |
92 | |
93 | /* |
94 | * Table index is stored in the media entry. |
95 | */ |
96 | #ifdef DIAGNOSTIC1 |
97 | if (ife->ifm_data >= MII_NMEDIA10) |
98 | panic("mii_phy_setmedia"); |
99 | #endif |
100 | |
101 | anar = mii_media_table[ife->ifm_data].mm_anar; |
102 | bmcr = mii_media_table[ife->ifm_data].mm_bmcr; |
103 | gtcr = mii_media_table[ife->ifm_data].mm_gtcr; |
104 | |
105 | if (mii->mii_media.ifm_media & IFM_ETH_MASTER0x0000000000010000ULL) { |
106 | switch (IFM_SUBTYPE(ife->ifm_media)((ife->ifm_media) & 0x00000000000000ffULL)) { |
107 | case IFM_1000_T16: |
108 | gtcr |= GTCR_MAN_MS0x1000|GTCR_ADV_MS0x0800; |
109 | break; |
110 | |
111 | default: |
112 | panic("mii_phy_setmedia: MASTER on wrong media"); |
113 | } |
114 | } |
115 | |
116 | if (ife->ifm_media & IFM_LOOP0x0000800000000000ULL) |
117 | bmcr |= BMCR_LOOP0x4000; |
118 | |
119 | PHY_WRITE(sc, MII_ANAR, anar)(*(sc)->mii_pdata->mii_writereg)((sc)->mii_dev.dv_parent , (sc)->mii_phy, (0x04), (anar)); |
120 | PHY_WRITE(sc, MII_BMCR, bmcr)(*(sc)->mii_pdata->mii_writereg)((sc)->mii_dev.dv_parent , (sc)->mii_phy, (0x00), (bmcr)); |
121 | if (sc->mii_flags & MIIF_HAVE_GTCR0x0040) |
122 | PHY_WRITE(sc, MII_100T2CR, gtcr)(*(sc)->mii_pdata->mii_writereg)((sc)->mii_dev.dv_parent , (sc)->mii_phy, (0x09), (gtcr)); |
123 | } |
124 | |
125 | int |
126 | mii_phy_auto(struct mii_softc *sc, int waitfor) |
127 | { |
128 | int bmsr, i; |
129 | |
130 | if ((sc->mii_flags & MIIF_DOINGAUTO0x0008) == 0) { |
131 | /* |
132 | * Check for 1000BASE-X. Autonegotiation is a bit |
133 | * different on such devices. |
134 | */ |
135 | if (sc->mii_flags & MIIF_IS_1000X0x0080) { |
136 | uint16_t anar = 0; |
137 | |
138 | if (sc->mii_extcapabilities & EXTSR_1000XFDX0x8000) |
139 | anar |= ANAR_X_FD0x0020; |
140 | if (sc->mii_extcapabilities & EXTSR_1000XHDX0x4000) |
141 | anar |= ANAR_X_HD0x0040; |
142 | |
143 | if (sc->mii_flags & MIIF_DOPAUSE0x0100 && |
144 | sc->mii_extcapabilities & EXTSR_1000XFDX0x8000) |
145 | anar |= ANAR_X_PAUSE_TOWARDS(3 << 7); |
146 | |
147 | PHY_WRITE(sc, MII_ANAR, anar)(*(sc)->mii_pdata->mii_writereg)((sc)->mii_dev.dv_parent , (sc)->mii_phy, (0x04), (anar)); |
148 | } else { |
149 | uint16_t anar; |
150 | |
151 | anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities)(((sc->mii_capabilities) & (0x8000|0x4000|0x2000| 0x1000 |0x0800|0x0400|0x0200)) >> 6) | |
152 | ANAR_CSMA0x0001; |
153 | /* |
154 | * Most 100baseTX PHY's only support symmetric |
155 | * PAUSE, so we don't advertise asymmetric |
156 | * PAUSE unless we also have 1000baseT capability. |
157 | */ |
158 | if (sc->mii_flags & MIIF_DOPAUSE0x0100) { |
159 | if (sc->mii_capabilities & BMSR_100TXFDX0x4000) |
160 | anar |= ANAR_FC0x0400; |
161 | if (sc->mii_extcapabilities & EXTSR_1000TFDX0x2000) |
162 | anar |= ANAR_PAUSE_TOWARDS(3 << 10); |
163 | } |
164 | PHY_WRITE(sc, MII_ANAR, anar)(*(sc)->mii_pdata->mii_writereg)((sc)->mii_dev.dv_parent , (sc)->mii_phy, (0x04), (anar)); |
165 | if (sc->mii_flags & MIIF_HAVE_GTCR0x0040) { |
166 | uint16_t gtcr = 0; |
167 | |
168 | if (sc->mii_extcapabilities & EXTSR_1000TFDX0x2000) |
169 | gtcr |= GTCR_ADV_1000TFDX0x0200; |
170 | if (sc->mii_extcapabilities & EXTSR_1000THDX0x1000) |
171 | gtcr |= GTCR_ADV_1000THDX0x0100; |
172 | |
173 | PHY_WRITE(sc, MII_100T2CR, gtcr)(*(sc)->mii_pdata->mii_writereg)((sc)->mii_dev.dv_parent , (sc)->mii_phy, (0x09), (gtcr)); |
174 | } |
175 | } |
176 | PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG)(*(sc)->mii_pdata->mii_writereg)((sc)->mii_dev.dv_parent , (sc)->mii_phy, (0x00), (0x1000 | 0x0200)); |
177 | } |
178 | |
179 | if (waitfor) { |
180 | /* Wait 500ms for it to complete. */ |
181 | for (i = 0; i < 500; i++) { |
182 | if ((bmsr = PHY_READ(sc, MII_BMSR)(*(sc)->mii_pdata->mii_readreg)((sc)->mii_dev.dv_parent , (sc)->mii_phy, (0x01))) & BMSR_ACOMP0x0020) |
Although the value stored to 'bmsr' is used in the enclosing expression, the value is never actually read from 'bmsr' | |
183 | return (0); |
184 | delay(1000)(*delay_func)(1000); |
185 | } |
186 | |
187 | /* |
188 | * Don't need to worry about clearing MIIF_DOINGAUTO. |
189 | * If that's set, a timeout is pending, and it will |
190 | * clear the flag. |
191 | */ |
192 | return (EIO5); |
193 | } |
194 | |
195 | /* |
196 | * Just let it finish asynchronously. This is for the benefit of |
197 | * the tick handler driving autonegotiation. Don't want 500ms |
198 | * delays all the time while the system is running! |
199 | */ |
200 | if (sc->mii_flags & MIIF_AUTOTSLEEP0x0010) { |
201 | sc->mii_flags |= MIIF_DOINGAUTO0x0008; |
202 | tsleep_nsec(&sc->mii_flags, PZERO22, "miiaut", MSEC_TO_NSEC(500)); |
203 | mii_phy_auto_timeout(sc); |
204 | } else if ((sc->mii_flags & MIIF_DOINGAUTO0x0008) == 0) { |
205 | sc->mii_flags |= MIIF_DOINGAUTO0x0008; |
206 | timeout_set(&sc->mii_phy_timo, mii_phy_auto_timeout, sc); |
207 | timeout_add_msec(&sc->mii_phy_timo, 500); |
208 | } |
209 | return (EJUSTRETURN-2); |
210 | } |
211 | |
212 | void |
213 | mii_phy_auto_timeout(void *arg) |
214 | { |
215 | struct mii_softc *sc = arg; |
216 | int s, bmsr; |
217 | |
218 | if ((sc->mii_dev.dv_flags & DVF_ACTIVE0x0001) == 0) |
219 | return; |
220 | |
221 | s = splnet()splraise(0x4); |
222 | sc->mii_flags &= ~MIIF_DOINGAUTO0x0008; |
223 | bmsr = PHY_READ(sc, MII_BMSR)(*(sc)->mii_pdata->mii_readreg)((sc)->mii_dev.dv_parent , (sc)->mii_phy, (0x01)); |
224 | |
225 | /* Update the media status. */ |
226 | (void) PHY_SERVICE(sc, sc->mii_pdata, MII_POLLSTAT)(*(sc)->mii_funcs->pf_service)((sc), (sc->mii_pdata) , (3)); |
227 | splx(s)spllower(s); |
228 | } |
229 | |
230 | int |
231 | mii_phy_tick(struct mii_softc *sc) |
232 | { |
233 | struct mii_data *mii = sc->mii_pdata; |
234 | struct ifmedia_entry *ife = mii->mii_media.ifm_cur; |
235 | int reg; |
236 | |
237 | /* Just bail now if the interface is down. */ |
238 | if ((mii->mii_ifp->if_flags & IFF_UP0x1) == 0) |
239 | return (EJUSTRETURN-2); |
240 | |
241 | /* |
242 | * If we're not doing autonegotiation, we don't need to do |
243 | * any extra work here. However, we need to check the link |
244 | * status so we can generate an announcement if the status |
245 | * changes. |
246 | */ |
247 | if (IFM_SUBTYPE(ife->ifm_media)((ife->ifm_media) & 0x00000000000000ffULL) != IFM_AUTO0ULL) |
248 | return (0); |
249 | |
250 | /* Read the status register twice; BMSR_LINK is latch-low. */ |
251 | reg = PHY_READ(sc, MII_BMSR)(*(sc)->mii_pdata->mii_readreg)((sc)->mii_dev.dv_parent , (sc)->mii_phy, (0x01)) | PHY_READ(sc, MII_BMSR)(*(sc)->mii_pdata->mii_readreg)((sc)->mii_dev.dv_parent , (sc)->mii_phy, (0x01)); |
252 | if (reg & BMSR_LINK0x0004) { |
253 | /* |
254 | * See above. |
255 | */ |
256 | return (0); |
257 | } |
258 | |
259 | /* |
260 | * Only retry autonegotiation every mii_anegticks seconds. |
261 | */ |
262 | if (!sc->mii_anegticks) |
263 | sc->mii_anegticks = MII_ANEGTICKS5; |
264 | |
265 | if (++sc->mii_ticks <= sc->mii_anegticks) |
266 | return (EJUSTRETURN-2); |
267 | |
268 | sc->mii_ticks = 0; |
269 | PHY_RESET(sc)(*(sc)->mii_funcs->pf_reset)((sc)); |
270 | |
271 | if (mii_phy_auto(sc, 0) == EJUSTRETURN-2) |
272 | return (EJUSTRETURN-2); |
273 | |
274 | /* |
275 | * Might need to generate a status message if autonegotiation |
276 | * failed. |
277 | */ |
278 | return (0); |
279 | } |
280 | |
281 | void |
282 | mii_phy_reset(struct mii_softc *sc) |
283 | { |
284 | int reg, i; |
285 | |
286 | if (sc->mii_flags & MIIF_NOISOLATE0x0002) |
287 | reg = BMCR_RESET0x8000; |
288 | else |
289 | reg = BMCR_RESET0x8000 | BMCR_ISO0x0400; |
290 | PHY_WRITE(sc, MII_BMCR, reg)(*(sc)->mii_pdata->mii_writereg)((sc)->mii_dev.dv_parent , (sc)->mii_phy, (0x00), (reg)); |
291 | |
292 | /* |
293 | * It is best to allow a little time for the reset to settle |
294 | * in before we start polling the BMCR again. Notably, the |
295 | * DP83840A manual states that there should be a 500us delay |
296 | * between asserting software reset and attempting MII serial |
297 | * operations. Also, a DP83815 can get into a bad state on |
298 | * cable removal and reinsertion if we do not delay here. |
299 | */ |
300 | delay(500)(*delay_func)(500); |
301 | |
302 | /* Wait another 100ms for it to complete. */ |
303 | for (i = 0; i < 100; i++) { |
304 | reg = PHY_READ(sc, MII_BMCR)(*(sc)->mii_pdata->mii_readreg)((sc)->mii_dev.dv_parent , (sc)->mii_phy, (0x00)); |
305 | if ((reg & BMCR_RESET0x8000) == 0) |
306 | break; |
307 | delay(1000)(*delay_func)(1000); |
308 | } |
309 | |
310 | if (sc->mii_inst != 0 && ((sc->mii_flags & MIIF_NOISOLATE0x0002) == 0)) |
311 | PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO)(*(sc)->mii_pdata->mii_writereg)((sc)->mii_dev.dv_parent , (sc)->mii_phy, (0x00), (reg | 0x0400)); |
312 | } |
313 | |
314 | void |
315 | mii_phy_down(struct mii_softc *sc) |
316 | { |
317 | if (sc->mii_flags & MIIF_DOINGAUTO0x0008) { |
318 | sc->mii_flags &= ~MIIF_DOINGAUTO0x0008; |
319 | timeout_del(&sc->mii_phy_timo); |
320 | } |
321 | } |
322 | |
323 | |
324 | void |
325 | mii_phy_status(struct mii_softc *sc) |
326 | { |
327 | PHY_STATUS(sc)(*(sc)->mii_funcs->pf_status)((sc)); |
328 | } |
329 | |
330 | void |
331 | mii_phy_update(struct mii_softc *sc, int cmd) |
332 | { |
333 | struct mii_data *mii = sc->mii_pdata; |
334 | struct ifnet *ifp = mii->mii_ifp; |
335 | int announce, s; |
336 | |
337 | if (sc->mii_media_active != mii->mii_media_active || |
338 | sc->mii_media_status != mii->mii_media_status || |
339 | cmd == MII_MEDIACHG2) { |
340 | announce = mii_phy_statusmsg(sc); |
341 | (*mii->mii_statchg)(sc->mii_dev.dv_parent); |
342 | sc->mii_media_active = mii->mii_media_active; |
343 | sc->mii_media_status = mii->mii_media_status; |
344 | |
345 | if (announce) { |
346 | s = splnet()splraise(0x4); |
347 | if_link_state_change(ifp); |
348 | splx(s)spllower(s); |
349 | } |
350 | } |
351 | } |
352 | |
353 | int |
354 | mii_phy_statusmsg(struct mii_softc *sc) |
355 | { |
356 | struct mii_data *mii = sc->mii_pdata; |
357 | struct ifnet *ifp = mii->mii_ifp; |
358 | u_int64_t baudrate; |
359 | int link_state, announce = 0; |
360 | |
361 | if (mii->mii_media_status & IFM_AVALID0x0000000000000001ULL) { |
362 | if (mii->mii_media_status & IFM_ACTIVE0x0000000000000002ULL) { |
363 | if (mii->mii_media_active & IFM_FDX0x0000010000000000ULL) |
364 | link_state = LINK_STATE_FULL_DUPLEX6; |
365 | else |
366 | link_state = LINK_STATE_HALF_DUPLEX5; |
367 | } else |
368 | link_state = LINK_STATE_DOWN2; |
369 | } else |
370 | link_state = LINK_STATE_UNKNOWN0; |
371 | |
372 | baudrate = ifmedia_baudrate(mii->mii_media_active); |
373 | |
374 | if (link_state != ifp->if_link_stateif_data.ifi_link_state) { |
375 | ifp->if_link_stateif_data.ifi_link_state = link_state; |
376 | /* |
377 | * XXX Right here we'd like to notify protocols |
378 | * XXX that the link status has changed, so that |
379 | * XXX e.g. Duplicate Address Detection can restart. |
380 | */ |
381 | announce = 1; |
382 | } |
383 | |
384 | if (baudrate != ifp->if_baudrateif_data.ifi_baudrate) { |
385 | ifp->if_baudrateif_data.ifi_baudrate = baudrate; |
386 | announce = 1; |
387 | } |
388 | |
389 | return (announce); |
390 | } |
391 | |
392 | /* |
393 | * Initialize generic PHY media based on BMSR, called when a PHY is |
394 | * attached. |
395 | */ |
396 | void |
397 | mii_phy_add_media(struct mii_softc *sc) |
398 | { |
399 | struct mii_data *mii = sc->mii_pdata; |
400 | |
401 | #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL((void *)0)) |
402 | |
403 | if ((sc->mii_flags & MIIF_NOISOLATE0x0002) == 0) |
404 | ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst)((0x0000000000000100ULL) | (2ULL) | (0) | ((uint64_t)(sc-> mii_inst) << 56)), |
405 | MII_MEDIA_NONE0); |
406 | |
407 | if (sc->mii_capabilities & BMSR_10THDX0x0800) { |
408 | ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst)((0x0000000000000100ULL) | (3) | (0) | ((uint64_t)(sc->mii_inst ) << 56)), |
409 | MII_MEDIA_10_T1); |
410 | } |
411 | if (sc->mii_capabilities & BMSR_10TFDX0x1000) { |
412 | ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst)((0x0000000000000100ULL) | (3) | (0x0000010000000000ULL) | (( uint64_t)(sc->mii_inst) << 56)), |
413 | MII_MEDIA_10_T_FDX2); |
414 | } |
415 | if (sc->mii_capabilities & BMSR_100TXHDX0x2000) { |
416 | ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst)((0x0000000000000100ULL) | (6) | (0) | ((uint64_t)(sc->mii_inst ) << 56)), |
417 | MII_MEDIA_100_TX4); |
418 | } |
419 | if (sc->mii_capabilities & BMSR_100TXFDX0x4000) { |
420 | ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst)((0x0000000000000100ULL) | (6) | (0x0000010000000000ULL) | (( uint64_t)(sc->mii_inst) << 56)), |
421 | MII_MEDIA_100_TX_FDX5); |
422 | } |
423 | if (sc->mii_capabilities & BMSR_100T40x8000) { |
424 | ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, 0, sc->mii_inst)((0x0000000000000100ULL) | (8) | (0) | ((uint64_t)(sc->mii_inst ) << 56)), |
425 | MII_MEDIA_100_T43); |
426 | } |
427 | if (sc->mii_extcapabilities & EXTSR_MEDIAMASK(0x8000|0x4000| 0x2000|0x1000)) { |
428 | /* |
429 | * XXX Right now only handle 1000SX and 1000TX. Need |
430 | * XXX to handle 1000LX and 1000CX some how. |
431 | */ |
432 | if (sc->mii_extcapabilities & EXTSR_1000XHDX0x4000) { |
433 | sc->mii_anegticks = MII_ANEGTICKS_GIGE10; |
434 | sc->mii_flags |= MIIF_IS_1000X0x0080; |
435 | ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0,((0x0000000000000100ULL) | (11) | (0) | ((uint64_t)(sc->mii_inst ) << 56)) |
436 | sc->mii_inst)((0x0000000000000100ULL) | (11) | (0) | ((uint64_t)(sc->mii_inst ) << 56)), MII_MEDIA_1000_X6); |
437 | } |
438 | if (sc->mii_extcapabilities & EXTSR_1000XFDX0x8000) { |
439 | sc->mii_anegticks = MII_ANEGTICKS_GIGE10; |
440 | sc->mii_flags |= MIIF_IS_1000X0x0080; |
441 | ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX,((0x0000000000000100ULL) | (11) | (0x0000010000000000ULL) | ( (uint64_t)(sc->mii_inst) << 56)) |
442 | sc->mii_inst)((0x0000000000000100ULL) | (11) | (0x0000010000000000ULL) | ( (uint64_t)(sc->mii_inst) << 56)), MII_MEDIA_1000_X_FDX7); |
443 | } |
444 | |
445 | /* |
446 | * 1000baseT media needs to be able to manipulate |
447 | * master/slave mode. We set IFM_ETH_MASTER in |
448 | * the "don't care mask" and filter it out when |
449 | * the media is set. |
450 | * |
451 | * All 1000baseT PHYs have a 1000baseT control register. |
452 | */ |
453 | if (sc->mii_extcapabilities & EXTSR_1000THDX0x1000) { |
454 | sc->mii_anegticks = MII_ANEGTICKS_GIGE10; |
455 | sc->mii_flags |= MIIF_HAVE_GTCR0x0040; |
456 | mii->mii_media.ifm_mask |= IFM_ETH_MASTER0x0000000000010000ULL; |
457 | ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0,((0x0000000000000100ULL) | (16) | (0) | ((uint64_t)(sc->mii_inst ) << 56)) |
458 | sc->mii_inst)((0x0000000000000100ULL) | (16) | (0) | ((uint64_t)(sc->mii_inst ) << 56)), MII_MEDIA_1000_T8); |
459 | } |
460 | if (sc->mii_extcapabilities & EXTSR_1000TFDX0x2000) { |
461 | sc->mii_anegticks = MII_ANEGTICKS_GIGE10; |
462 | sc->mii_flags |= MIIF_HAVE_GTCR0x0040; |
463 | mii->mii_media.ifm_mask |= IFM_ETH_MASTER0x0000000000010000ULL; |
464 | ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX,((0x0000000000000100ULL) | (16) | (0x0000010000000000ULL) | ( (uint64_t)(sc->mii_inst) << 56)) |
465 | sc->mii_inst)((0x0000000000000100ULL) | (16) | (0x0000010000000000ULL) | ( (uint64_t)(sc->mii_inst) << 56)), MII_MEDIA_1000_T_FDX9); |
466 | } |
467 | } |
468 | |
469 | if (sc->mii_capabilities & BMSR_ANEG0x0008) { |
470 | ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst)((0x0000000000000100ULL) | (0ULL) | (0) | ((uint64_t)(sc-> mii_inst) << 56)), |
471 | MII_NMEDIA10); /* intentionally invalid index */ |
472 | } |
473 | #undef ADD |
474 | } |
475 | |
476 | void |
477 | mii_phy_delete_media(struct mii_softc *sc) |
478 | { |
479 | struct mii_data *mii = sc->mii_pdata; |
480 | |
481 | ifmedia_delete_instance(&mii->mii_media, sc->mii_inst); |
482 | } |
483 | |
484 | int |
485 | mii_phy_detach(struct device *self, int flags) |
486 | { |
487 | struct mii_softc *sc = (void *) self; |
488 | |
489 | if (sc->mii_flags & MIIF_DOINGAUTO0x0008) |
490 | timeout_del(&sc->mii_phy_timo); |
491 | |
492 | mii_phy_delete_media(sc); |
493 | |
494 | return (0); |
495 | } |
496 | |
497 | const struct mii_phydesc * |
498 | mii_phy_match(const struct mii_attach_args *ma, const struct mii_phydesc *mpd) |
499 | { |
500 | |
501 | for (; mpd->mpd_name != NULL((void *)0); mpd++) { |
502 | if (MII_OUI(ma->mii_id1, ma->mii_id2)(((ma->mii_id1) << 6) | ((ma->mii_id2) >> 10 )) == mpd->mpd_oui && |
503 | MII_MODEL(ma->mii_id2)(((ma->mii_id2) & 0x03f0) >> 4) == mpd->mpd_model) |
504 | return (mpd); |
505 | } |
506 | return (NULL((void *)0)); |
507 | } |
508 | |
509 | /* |
510 | * Return the flow control status flag from MII_ANAR & MII_ANLPAR. |
511 | */ |
512 | uint64_t |
513 | mii_phy_flowstatus(struct mii_softc *sc) |
514 | { |
515 | int anar, anlpar; |
516 | |
517 | if ((sc->mii_flags & MIIF_DOPAUSE0x0100) == 0) |
518 | return (0); |
519 | |
520 | anar = PHY_READ(sc, MII_ANAR)(*(sc)->mii_pdata->mii_readreg)((sc)->mii_dev.dv_parent , (sc)->mii_phy, (0x04)); |
521 | anlpar = PHY_READ(sc, MII_ANLPAR)(*(sc)->mii_pdata->mii_readreg)((sc)->mii_dev.dv_parent , (sc)->mii_phy, (0x05)); |
522 | |
523 | /* For 1000baseX, the bits are in a different location. */ |
524 | if (sc->mii_flags & MIIF_IS_1000X0x0080) { |
525 | anar <<= 3; |
526 | anlpar <<= 3; |
527 | } |
528 | |
529 | if ((anar & ANAR_PAUSE_SYM(1 << 10)) & (anlpar & ANLPAR_PAUSE_SYM(1 << 10))) |
530 | return (IFM_FLOW0x0000040000000000ULL|IFM_ETH_TXPAUSE0x0000000000040000ULL|IFM_ETH_RXPAUSE0x0000000000020000ULL); |
531 | |
532 | if ((anar & ANAR_PAUSE_SYM(1 << 10)) == 0) { |
533 | if ((anar & ANAR_PAUSE_ASYM(2 << 10)) && |
534 | ((anlpar & ANLPAR_PAUSE_TOWARDS(3 << 10)) == ANLPAR_PAUSE_TOWARDS(3 << 10))) |
535 | return (IFM_FLOW0x0000040000000000ULL|IFM_ETH_TXPAUSE0x0000000000040000ULL); |
536 | else |
537 | return (0); |
538 | } |
539 | |
540 | if ((anar & ANAR_PAUSE_ASYM(2 << 10)) == 0) { |
541 | if (anlpar & ANLPAR_PAUSE_SYM(1 << 10)) |
542 | return (IFM_FLOW0x0000040000000000ULL|IFM_ETH_TXPAUSE0x0000000000040000ULL|IFM_ETH_RXPAUSE0x0000000000020000ULL); |
543 | else |
544 | return (0); |
545 | } |
546 | |
547 | switch ((anlpar & ANLPAR_PAUSE_TOWARDS(3 << 10))) { |
548 | case ANLPAR_PAUSE_NONE(0 << 10): |
549 | return (0); |
550 | |
551 | case ANLPAR_PAUSE_ASYM(2 << 10): |
552 | return (IFM_FLOW0x0000040000000000ULL|IFM_ETH_RXPAUSE0x0000000000020000ULL); |
553 | |
554 | default: |
555 | return (IFM_FLOW0x0000040000000000ULL|IFM_ETH_RXPAUSE0x0000000000020000ULL|IFM_ETH_TXPAUSE0x0000000000040000ULL); |
556 | } |
557 | /* NOTREACHED */ |
558 | } |
559 | |
560 | /* |
561 | * Given an ifmedia word, return the corresponding ANAR value. |
562 | */ |
563 | int |
564 | mii_anar(uint64_t media) |
565 | { |
566 | int rv; |
567 | |
568 | switch (media & (IFM_TMASK0x00000000000000ffULL|IFM_NMASK0x000000000000ff00ULL|IFM_FDX0x0000010000000000ULL)) { |
569 | case IFM_ETHER0x0000000000000100ULL|IFM_10_T3: |
570 | rv = ANAR_100x0020|ANAR_CSMA0x0001; |
571 | break; |
572 | case IFM_ETHER0x0000000000000100ULL|IFM_10_T3|IFM_FDX0x0000010000000000ULL: |
573 | rv = ANAR_10_FD0x0040|ANAR_CSMA0x0001; |
574 | break; |
575 | case IFM_ETHER0x0000000000000100ULL|IFM_100_TX6: |
576 | rv = ANAR_TX0x0080|ANAR_CSMA0x0001; |
577 | break; |
578 | case IFM_ETHER0x0000000000000100ULL|IFM_100_TX6|IFM_FDX0x0000010000000000ULL: |
579 | rv = ANAR_TX_FD0x0100|ANAR_CSMA0x0001; |
580 | break; |
581 | case IFM_ETHER0x0000000000000100ULL|IFM_100_T48: |
582 | rv = ANAR_T40x0200|ANAR_CSMA0x0001; |
583 | break; |
584 | default: |
585 | rv = 0; |
586 | break; |
587 | } |
588 | |
589 | return (rv); |
590 | } |