1 /* $NetBSD: mii_physubr.c,v 1.49 2006/03/29 07:05:24 thorpej Exp $ */
4 * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
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.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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.
39 * $FreeBSD: src/sys/dev/mii/mii_physubr.c,v 1.2.2.1 2000/12/12 19:29:14 wpaul Exp $
40 * $DragonFly: src/sys/dev/netif/mii_layer/mii_physubr.c,v 1.15 2008/07/22 10:59:16 sephe Exp $
44 * Subroutines common to all PHYs.
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/kernel.h>
50 #include <sys/socket.h>
51 #include <sys/errno.h>
52 #include <sys/module.h>
54 #include <sys/thread2.h>
57 #include <net/if_media.h>
62 #include "miibus_if.h"
64 const struct mii_media mii_media_table
[MII_NMEDIA
] = {
65 [MII_MEDIA_NONE
] = { .mm_bmcr
= BMCR_ISO
,
69 [MII_MEDIA_10_T
] = { .mm_bmcr
= BMCR_S10
,
70 .mm_anar
= ANAR_CSMA
| ANAR_10
,
73 [MII_MEDIA_10_T_FDX
] = { .mm_bmcr
= BMCR_S10
| BMCR_FDX
,
74 .mm_anar
= ANAR_CSMA
| ANAR_10_FD
,
77 [MII_MEDIA_100_T4
] = { .mm_bmcr
= BMCR_S100
,
78 .mm_anar
= ANAR_CSMA
| ANAR_T4
,
81 [MII_MEDIA_100_TX
] = { .mm_bmcr
= BMCR_S100
,
82 .mm_anar
= ANAR_CSMA
| ANAR_TX
,
85 [MII_MEDIA_100_TX_FDX
] = { .mm_bmcr
= BMCR_S100
| BMCR_FDX
,
86 .mm_anar
= ANAR_CSMA
| ANAR_TX_FD
,
89 [MII_MEDIA_1000_X
] = { .mm_bmcr
= BMCR_S1000
,
93 [MII_MEDIA_1000_X_FDX
] = { .mm_bmcr
= BMCR_S1000
| BMCR_FDX
,
97 [MII_MEDIA_1000_T
] = { .mm_bmcr
= BMCR_S1000
,
99 .mm_gtcr
= GTCR_ADV_1000THDX
},
101 [MII_MEDIA_1000_T_FDX
] = { .mm_bmcr
= BMCR_S1000
,
102 .mm_anar
= ANAR_CSMA
,
103 .mm_gtcr
= GTCR_ADV_1000TFDX
}
107 mii_softc_init(struct mii_softc
*mii
, struct mii_attach_args
*ma
)
109 mii
->mii_phy
= ma
->mii_phyno
;
110 mii
->mii_flags
|= ma
->mii_flags
;
111 mii
->mii_model
= MII_MODEL(ma
->mii_id2
);
112 mii
->mii_rev
= MII_REV(ma
->mii_id2
);
114 if (mii
->mii_reset
== NULL
)
115 mii
->mii_reset
= mii_phy_reset
;
116 if (mii
->mii_anegticks
== 0)
117 mii
->mii_anegticks
= MII_ANEGTICKS
;
121 mii_phy_auto(struct mii_softc
*sc
, int waitfor
)
126 * Check for 1000BASE-X. Autonegotiation is a bit
127 * different on such devices.
129 if (sc
->mii_flags
& MIIF_IS_1000X
) {
131 if (sc
->mii_extcapabilities
& EXTSR_1000XFDX
)
133 if (sc
->mii_extcapabilities
& EXTSR_1000XHDX
)
136 if (sc
->mii_flags
& MIIF_DOPAUSE
) {
137 /* XXX Asymmetric vs. symmetric? */
138 anar
|= ANLPAR_X_PAUSE_TOWARDS
;
140 PHY_WRITE(sc
, MII_ANAR
, anar
);
142 anar
= BMSR_MEDIA_TO_ANAR(sc
->mii_capabilities
) |
144 if (sc
->mii_flags
& MIIF_DOPAUSE
) {
146 /* XXX Only 1000BASE-T has PAUSE_ASYM? */
147 if ((sc
->mii_flags
& MIIF_HAVE_GTCR
) &&
148 (sc
->mii_extcapabilities
&
149 (EXTSR_1000THDX
|EXTSR_1000TFDX
)))
150 anar
|= ANAR_X_PAUSE_ASYM
;
152 PHY_WRITE(sc
, MII_ANAR
, anar
);
153 if (sc
->mii_flags
& MIIF_HAVE_GTCR
) {
156 if (sc
->mii_extcapabilities
& EXTSR_1000TFDX
)
157 gtcr
|= GTCR_ADV_1000TFDX
;
158 if (sc
->mii_extcapabilities
& EXTSR_1000THDX
)
159 gtcr
|= GTCR_ADV_1000THDX
;
161 PHY_WRITE(sc
, MII_100T2CR
, gtcr
);
164 PHY_WRITE(sc
, MII_BMCR
, BMCR_AUTOEN
| BMCR_STARTNEG
);
169 /* Wait 500ms for it to complete. */
170 for (i
= 0; i
< 500; i
++) {
171 if (PHY_READ(sc
, MII_BMSR
) & BMSR_ACOMP
)
177 return (EJUSTRETURN
);
181 mii_phy_reset(struct mii_softc
*sc
)
185 if (sc
->mii_flags
& MIIF_NOISOLATE
)
188 reg
= BMCR_RESET
| BMCR_ISO
;
189 PHY_WRITE(sc
, MII_BMCR
, reg
);
192 * It is best to allow a little time for the reset to settle
193 * in before we start polling the BMCR again. Notably, the
194 * DP83840A manual states that there should be a 500us delay
195 * between asserting software reset and attempting MII serial
196 * operations. Also, a DP83815 can get into a bad state on
197 * cable removal and reinsertion if we do not delay here.
201 /* Wait 100ms for it to complete. */
202 for (i
= 0; i
< 100; i
++) {
203 reg
= PHY_READ(sc
, MII_BMCR
);
204 if ((reg
& BMCR_RESET
) == 0)
209 if (sc
->mii_inst
!= 0 && ((sc
->mii_flags
& MIIF_NOISOLATE
) == 0))
210 PHY_WRITE(sc
, MII_BMCR
, reg
| BMCR_ISO
);
214 * Initialize generic PHY media based on BMSR, called when a PHY is
215 * attached. We expect to be set up to print a comma-separated list
216 * of media names. Does not print a newline.
219 mii_phy_add_media(struct mii_softc
*sc
)
221 struct mii_data
*mii
= sc
->mii_pdata
;
222 const char *sep
= "";
225 #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
226 #define PRINT(s) kprintf("%s%s", sep, s); sep = ", "
228 if ((sc
->mii_flags
& MIIF_NOISOLATE
) == 0)
229 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_NONE
, 0, sc
->mii_inst
),
233 * There are different interpretations for the bits in
234 * HomePNA PHYs. And there is really only one media type
237 if (sc
->mii_flags
& MIIF_IS_HPNA
) {
238 if (sc
->mii_capabilities
& BMSR_10THDX
) {
239 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_HPNA_1
, 0,
247 if (sc
->mii_capabilities
& BMSR_10THDX
) {
248 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_10_T
, 0, sc
->mii_inst
),
252 if (sc
->mii_capabilities
& BMSR_10TFDX
) {
253 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_10_T
, IFM_FDX
, sc
->mii_inst
),
255 PRINT("10baseT-FDX");
258 if (sc
->mii_capabilities
& BMSR_100TXHDX
) {
259 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_100_TX
, 0, sc
->mii_inst
),
263 if (sc
->mii_capabilities
& BMSR_100TXFDX
) {
264 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_100_TX
, IFM_FDX
, sc
->mii_inst
),
265 MII_MEDIA_100_TX_FDX
);
266 PRINT("100baseTX-FDX");
269 if (sc
->mii_capabilities
& BMSR_100T4
) {
270 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_100_T4
, 0, sc
->mii_inst
),
275 if (sc
->mii_extcapabilities
& EXTSR_MEDIAMASK
) {
277 * XXX Right now only handle 1000SX and 1000TX. Need
278 * XXX to handle 1000LX and 1000CX some how.
280 * Note since it can take 5 seconds to auto-negotiate
281 * a gigabit link, we make anegticks 10 seconds for
282 * all the gigabit media types.
284 if (sc
->mii_extcapabilities
& EXTSR_1000XHDX
) {
285 sc
->mii_anegticks
= MII_ANEGTICKS_GIGE
;
286 sc
->mii_flags
|= MIIF_IS_1000X
;
287 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_1000_SX
, 0,
288 sc
->mii_inst
), MII_MEDIA_1000_X
);
291 if (sc
->mii_extcapabilities
& EXTSR_1000XFDX
) {
292 sc
->mii_anegticks
= MII_ANEGTICKS_GIGE
;
293 sc
->mii_flags
|= MIIF_IS_1000X
;
294 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_1000_SX
, IFM_FDX
,
295 sc
->mii_inst
), MII_MEDIA_1000_X_FDX
);
296 PRINT("1000baseSX-FDX");
301 * 1000baseT media needs to be able to manipulate
302 * master/slave mode. We set IFM_ETH_MASTER in
303 * the "don't care mask" and filter it out when
306 * All 1000baseT PHYs have a 1000baseT control register.
308 if (sc
->mii_extcapabilities
& EXTSR_1000THDX
) {
309 sc
->mii_anegticks
= MII_ANEGTICKS_GIGE
;
310 sc
->mii_flags
|= MIIF_HAVE_GTCR
;
311 mii
->mii_media
.ifm_mask
|= IFM_ETH_MASTER
;
312 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_1000_T
, 0,
313 sc
->mii_inst
), MII_MEDIA_1000_T
);
316 if (sc
->mii_extcapabilities
& EXTSR_1000TFDX
) {
317 sc
->mii_anegticks
= MII_ANEGTICKS_GIGE
;
318 sc
->mii_flags
|= MIIF_HAVE_GTCR
;
319 mii
->mii_media
.ifm_mask
|= IFM_ETH_MASTER
;
320 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_1000_T
, IFM_FDX
,
321 sc
->mii_inst
), MII_MEDIA_1000_T_FDX
);
322 PRINT("1000baseT-FDX");
327 if (sc
->mii_capabilities
& BMSR_ANEG
) {
328 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_AUTO
, 0, sc
->mii_inst
),
329 MII_NMEDIA
); /* intentionally invalid index */
334 if (fdx
!= 0 && (sc
->mii_flags
& MIIF_DOPAUSE
))
335 mii
->mii_media
.ifm_mask
|= IFM_ETH_FMASK
;
339 mii_phy_set_media(struct mii_softc
*sc
)
341 struct mii_data
*mii
= sc
->mii_pdata
;
342 struct ifmedia_entry
*ife
= mii
->mii_media
.ifm_cur
;
343 int bmcr
, anar
, gtcr
;
345 if (IFM_SUBTYPE(ife
->ifm_media
) == IFM_AUTO
) {
347 * Force renegotiation if MIIF_DOPAUSE.
349 * XXX This is only necessary because many NICs don't
350 * XXX advertise PAUSE capabilities at boot time. Maybe
351 * XXX we should force this only once?
353 if ((PHY_READ(sc
, MII_BMCR
) & BMCR_AUTOEN
) == 0 ||
354 (sc
->mii_flags
& (MIIF_FORCEANEG
| MIIF_DOPAUSE
)))
360 * Table index is stored in the media entry.
363 KASSERT(ife
->ifm_data
>= 0 && ife
->ifm_data
< MII_NMEDIA
,
364 ("bogus ife->ifm_data (%d)\n", ife
->ifm_data
));
366 anar
= mii_media_table
[ife
->ifm_data
].mm_anar
;
367 bmcr
= mii_media_table
[ife
->ifm_data
].mm_bmcr
;
368 gtcr
= mii_media_table
[ife
->ifm_data
].mm_gtcr
;
370 if (mii
->mii_media
.ifm_media
& IFM_ETH_MASTER
) {
371 switch (IFM_SUBTYPE(ife
->ifm_media
)) {
373 gtcr
|= GTCR_MAN_MS
|GTCR_ADV_MS
;
377 panic("mii_phy_setmedia: MASTER on wrong media");
381 if (mii
->mii_media
.ifm_media
& IFM_FLOW
) {
382 if (sc
->mii_flags
& MIIF_IS_1000X
) {
383 anar
|= ANAR_X_PAUSE_SYM
| ANAR_X_PAUSE_ASYM
;
386 /* XXX Only 1000BASE-T has PAUSE_ASYM? */
387 if ((sc
->mii_flags
& MIIF_HAVE_GTCR
) &&
388 (sc
->mii_extcapabilities
&
389 (EXTSR_1000THDX
| EXTSR_1000TFDX
)))
390 anar
|= ANAR_X_PAUSE_ASYM
;
394 if (ife
->ifm_media
& IFM_LOOP
)
397 PHY_WRITE(sc
, MII_ANAR
, anar
);
398 PHY_WRITE(sc
, MII_BMCR
, bmcr
);
399 if (sc
->mii_flags
& MIIF_HAVE_GTCR
)
400 PHY_WRITE(sc
, MII_100T2CR
, gtcr
);
404 mii_phy_tick(struct mii_softc
*sc
)
406 struct mii_data
*mii
= sc
->mii_pdata
;
407 struct ifmedia_entry
*ife
= mii
->mii_media
.ifm_cur
;
410 /* Just bail now if the interface is down. */
411 if ((mii
->mii_ifp
->if_flags
& IFF_UP
) == 0)
412 return (EJUSTRETURN
);
415 * If we're not doing autonegotiation, we don't need to do
416 * any extra work here. However, we need to check the link
417 * status so we can generate an announcement if the status
420 if (IFM_SUBTYPE(ife
->ifm_media
) != IFM_AUTO
)
423 /* Read the status register twice; BMSR_LINK is latch-low. */
424 reg
= PHY_READ(sc
, MII_BMSR
) | PHY_READ(sc
, MII_BMSR
);
425 if (reg
& BMSR_LINK
) {
430 /* Reset autonegotiation timer. */
436 * Only retry autonegotiation every N seconds.
438 KKASSERT(sc
->mii_anegticks
> 0);
439 if (++sc
->mii_ticks
<= sc
->mii_anegticks
)
440 return (EJUSTRETURN
);
443 sc
->mii_reset(sc
); /* Reset PHY */
444 mii_phy_auto(sc
, 0); /* Ignore EJUSTRETURN */
449 mii_phy_statusmsg(struct mii_softc
*sc
)
451 struct mii_data
*mii
= sc
->mii_pdata
;
452 struct ifnet
*ifp
= mii
->mii_ifp
;
453 int baudrate
, link_state
, announce
= 0;
455 if (mii
->mii_media_status
& IFM_AVALID
) {
456 if (mii
->mii_media_status
& IFM_ACTIVE
)
457 link_state
= LINK_STATE_UP
;
459 link_state
= LINK_STATE_DOWN
;
461 link_state
= LINK_STATE_UNKNOWN
;
463 baudrate
= ifmedia_baudrate(mii
->mii_media_active
);
465 if (link_state
!= ifp
->if_link_state
) {
466 ifp
->if_link_state
= link_state
;
468 * XXX Right here we'd like to notify protocols
469 * XXX that the link status has changed, so that
470 * XXX e.g. Duplicate Address Detection can restart.
475 if (baudrate
!= ifp
->if_baudrate
) {
476 ifp
->if_baudrate
= baudrate
;
484 mii_phy_update(struct mii_softc
*sc
, int cmd
)
486 struct mii_data
*mii
= sc
->mii_pdata
;
487 struct ifnet
*ifp
= mii
->mii_ifp
;
490 if (sc
->mii_media_active
!= mii
->mii_media_active
||
491 sc
->mii_media_status
!= mii
->mii_media_status
||
492 cmd
== MII_MEDIACHG
) {
493 announce
= mii_phy_statusmsg(sc
);
494 MIIBUS_STATCHG(sc
->mii_dev
);
495 sc
->mii_media_active
= mii
->mii_media_active
;
496 sc
->mii_media_status
= mii
->mii_media_status
;
500 if_link_state_change(ifp
);
507 * Return the flow control status flag from MII_ANAR & MII_ANLPAR.
510 mii_phy_flowstatus(struct mii_softc
*sc
)
514 if ((sc
->mii_flags
& MIIF_DOPAUSE
) == 0)
517 anar
= PHY_READ(sc
, MII_ANAR
);
518 anlpar
= PHY_READ(sc
, MII_ANLPAR
);
520 if ((anar
& ANAR_X_PAUSE_SYM
) & (anlpar
& ANLPAR_X_PAUSE_SYM
))
521 return (IFM_FLOW
| IFM_ETH_TXPAUSE
| IFM_ETH_RXPAUSE
);
523 if ((anar
& ANAR_X_PAUSE_SYM
) == 0) {
524 if ((anar
& ANAR_X_PAUSE_ASYM
) &&
525 ((anlpar
& ANLPAR_X_PAUSE_TOWARDS
) ==
526 ANLPAR_X_PAUSE_TOWARDS
))
527 return (IFM_FLOW
| IFM_ETH_TXPAUSE
);
532 if ((anar
& ANAR_X_PAUSE_ASYM
) == 0) {
533 if (anlpar
& ANLPAR_X_PAUSE_SYM
)
534 return (IFM_FLOW
| IFM_ETH_TXPAUSE
| IFM_ETH_RXPAUSE
);
539 switch (anlpar
& ANLPAR_X_PAUSE_TOWARDS
) {
540 case ANLPAR_X_PAUSE_NONE
:
543 case ANLPAR_X_PAUSE_ASYM
:
544 return (IFM_FLOW
| IFM_ETH_RXPAUSE
);
547 return (IFM_FLOW
| IFM_ETH_RXPAUSE
| IFM_ETH_TXPAUSE
);
552 const struct mii_phydesc
*
553 mii_phy_match(const struct mii_attach_args
*ma
, const struct mii_phydesc
*mpd
)
555 for (; mpd
->mpd_name
!= NULL
; mpd
++) {
556 if (MII_OUI(ma
->mii_id1
, ma
->mii_id2
) == mpd
->mpd_oui
&&
557 MII_MODEL(ma
->mii_id2
) == mpd
->mpd_model
)