1 /* $NetBSD: mii_physubr.c,v 1.65 2009/11/06 18:41:25 dyoung 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.
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
34 * Subroutines common to all PHYs.
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: mii_physubr.c,v 1.65 2009/11/06 18:41:25 dyoung Exp $");
40 #include <sys/param.h>
41 #include <sys/device.h>
42 #include <sys/systm.h>
43 #include <sys/kernel.h>
44 #include <sys/socket.h>
45 #include <sys/errno.h>
49 #include <net/if_media.h>
50 #include <net/route.h>
52 #include <dev/mii/mii.h>
53 #include <dev/mii/miivar.h>
55 static void mii_phy_statusmsg(struct mii_softc
*);
58 * Media to register setting conversion table. Order matters.
60 static const struct mii_media mii_media_table
[MII_NMEDIA
] = {
62 { BMCR_ISO
, ANAR_CSMA
,
66 { BMCR_S10
, ANAR_CSMA
|ANAR_10
,
70 { BMCR_S10
|BMCR_FDX
, ANAR_CSMA
|ANAR_10_FD
,
74 { BMCR_S100
, ANAR_CSMA
|ANAR_T4
,
78 { BMCR_S100
, ANAR_CSMA
|ANAR_TX
,
82 { BMCR_S100
|BMCR_FDX
, ANAR_CSMA
|ANAR_TX_FD
,
86 { BMCR_S1000
, ANAR_CSMA
,
90 { BMCR_S1000
|BMCR_FDX
, ANAR_CSMA
,
94 { BMCR_S1000
, ANAR_CSMA
,
98 { BMCR_S1000
, ANAR_CSMA
,
102 static void mii_phy_auto_timeout(void *);
105 mii_phy_setmedia(struct mii_softc
*sc
)
107 struct mii_data
*mii
= sc
->mii_pdata
;
108 struct ifmedia_entry
*ife
= mii
->mii_media
.ifm_cur
;
109 int bmcr
, anar
, gtcr
;
111 if (IFM_SUBTYPE(ife
->ifm_media
) == IFM_AUTO
) {
113 * Force renegotiation if MIIF_DOPAUSE.
115 * XXX This is only necessary because many NICs don't
116 * XXX advertise PAUSE capabilities at boot time. Maybe
117 * XXX we should force this only once?
119 if ((PHY_READ(sc
, MII_BMCR
) & BMCR_AUTOEN
) == 0 ||
120 (sc
->mii_flags
& (MIIF_FORCEANEG
|MIIF_DOPAUSE
)))
121 (void) mii_phy_auto(sc
, 1);
126 * Table index is stored in the media entry.
130 if (/* ife->ifm_data < 0 || */ ife
->ifm_data
>= MII_NMEDIA
)
131 panic("mii_phy_setmedia");
134 anar
= mii_media_table
[ife
->ifm_data
].mm_anar
;
135 bmcr
= mii_media_table
[ife
->ifm_data
].mm_bmcr
;
136 gtcr
= mii_media_table
[ife
->ifm_data
].mm_gtcr
;
138 if (mii
->mii_media
.ifm_media
& IFM_ETH_MASTER
) {
139 switch (IFM_SUBTYPE(ife
->ifm_media
)) {
141 gtcr
|= GTCR_MAN_MS
|GTCR_ADV_MS
;
145 panic("mii_phy_setmedia: MASTER on wrong media");
149 if (mii
->mii_media
.ifm_media
& IFM_FLOW
) {
150 if (sc
->mii_flags
& MIIF_IS_1000X
)
151 anar
|= ANAR_X_PAUSE_SYM
| ANAR_X_PAUSE_ASYM
;
154 /* XXX Only 1000BASE-T has PAUSE_ASYM? */
155 if ((sc
->mii_flags
& MIIF_HAVE_GTCR
) &&
156 (sc
->mii_extcapabilities
&
157 (EXTSR_1000THDX
|EXTSR_1000TFDX
)))
158 anar
|= ANAR_X_PAUSE_ASYM
;
162 if (ife
->ifm_media
& IFM_LOOP
)
165 PHY_WRITE(sc
, MII_ANAR
, anar
);
166 PHY_WRITE(sc
, MII_BMCR
, bmcr
);
167 if (sc
->mii_flags
& MIIF_HAVE_GTCR
)
168 PHY_WRITE(sc
, MII_100T2CR
, gtcr
);
172 mii_phy_auto(struct mii_softc
*sc
, int waitfor
)
176 if ((sc
->mii_flags
& MIIF_DOINGAUTO
) == 0) {
178 * Check for 1000BASE-X. Autonegotiation is a bit
179 * different on such devices.
181 if (sc
->mii_flags
& MIIF_IS_1000X
) {
184 if (sc
->mii_extcapabilities
& EXTSR_1000XFDX
)
186 if (sc
->mii_extcapabilities
& EXTSR_1000XHDX
)
189 if (sc
->mii_flags
& MIIF_DOPAUSE
) {
190 /* XXX Asymmetric vs. symmetric? */
191 anar
|= ANLPAR_X_PAUSE_TOWARDS
;
194 PHY_WRITE(sc
, MII_ANAR
, anar
);
198 anar
= BMSR_MEDIA_TO_ANAR(sc
->mii_capabilities
) |
200 if (sc
->mii_flags
& MIIF_DOPAUSE
) {
202 /* XXX Only 1000BASE-T has PAUSE_ASYM? */
203 if ((sc
->mii_flags
& MIIF_HAVE_GTCR
) &&
204 (sc
->mii_extcapabilities
&
205 (EXTSR_1000THDX
|EXTSR_1000TFDX
)))
206 anar
|= ANAR_X_PAUSE_ASYM
;
208 PHY_WRITE(sc
, MII_ANAR
, anar
);
209 if (sc
->mii_flags
& MIIF_HAVE_GTCR
) {
212 if (sc
->mii_extcapabilities
& EXTSR_1000TFDX
)
213 gtcr
|= GTCR_ADV_1000TFDX
;
214 if (sc
->mii_extcapabilities
& EXTSR_1000THDX
)
215 gtcr
|= GTCR_ADV_1000THDX
;
217 PHY_WRITE(sc
, MII_100T2CR
, gtcr
);
220 PHY_WRITE(sc
, MII_BMCR
, BMCR_AUTOEN
| BMCR_STARTNEG
);
224 /* Wait 500ms for it to complete. */
225 for (i
= 0; i
< 500; i
++) {
226 if (PHY_READ(sc
, MII_BMSR
) & BMSR_ACOMP
)
232 * Don't need to worry about clearing MIIF_DOINGAUTO.
233 * If that's set, a timeout is pending, and it will
240 * Just let it finish asynchronously. This is for the benefit of
241 * the tick handler driving autonegotiation. Don't want 500ms
242 * delays all the time while the system is running!
244 if (sc
->mii_flags
& MIIF_AUTOTSLEEP
) {
245 sc
->mii_flags
|= MIIF_DOINGAUTO
;
246 tsleep(&sc
->mii_flags
, PZERO
, "miiaut", hz
>> 1);
247 mii_phy_auto_timeout(sc
);
248 } else if ((sc
->mii_flags
& MIIF_DOINGAUTO
) == 0) {
249 sc
->mii_flags
|= MIIF_DOINGAUTO
;
250 callout_reset(&sc
->mii_nway_ch
, hz
>> 1,
251 mii_phy_auto_timeout
, sc
);
253 return (EJUSTRETURN
);
257 mii_phy_auto_timeout(void *arg
)
259 struct mii_softc
*sc
= arg
;
262 if (!device_is_active(sc
->mii_dev
))
266 sc
->mii_flags
&= ~MIIF_DOINGAUTO
;
268 /* Update the media status. */
269 (void) PHY_SERVICE(sc
, sc
->mii_pdata
, MII_POLLSTAT
);
274 mii_phy_tick(struct mii_softc
*sc
)
276 struct mii_data
*mii
= sc
->mii_pdata
;
277 struct ifmedia_entry
*ife
= mii
->mii_media
.ifm_cur
;
280 /* Just bail now if the interface is down. */
281 if ((mii
->mii_ifp
->if_flags
& IFF_UP
) == 0)
282 return (EJUSTRETURN
);
285 * If we're not doing autonegotiation, we don't need to do
286 * any extra work here. However, we need to check the link
287 * status so we can generate an announcement if the status
290 if (IFM_SUBTYPE(ife
->ifm_media
) != IFM_AUTO
)
293 /* Read the status register twice; BMSR_LINK is latch-low. */
294 reg
= PHY_READ(sc
, MII_BMSR
) | PHY_READ(sc
, MII_BMSR
);
295 if (reg
& BMSR_LINK
) {
303 * Only retry autonegotiation every N seconds.
305 KASSERT(sc
->mii_anegticks
!= 0);
306 if (++sc
->mii_ticks
<= sc
->mii_anegticks
)
307 return (EJUSTRETURN
);
312 if (mii_phy_auto(sc
, 0) == EJUSTRETURN
)
313 return (EJUSTRETURN
);
316 * Might need to generate a status message if autonegotiation
323 mii_phy_reset(struct mii_softc
*sc
)
327 if (sc
->mii_flags
& MIIF_NOISOLATE
)
330 reg
= BMCR_RESET
| BMCR_ISO
;
331 PHY_WRITE(sc
, MII_BMCR
, reg
);
333 /* Wait another 100ms for it to complete. */
334 for (i
= 0; i
< 100; i
++) {
335 reg
= PHY_READ(sc
, MII_BMCR
);
336 if ((reg
& BMCR_RESET
) == 0)
341 if (sc
->mii_inst
!= 0 && ((sc
->mii_flags
& MIIF_NOISOLATE
) == 0))
342 PHY_WRITE(sc
, MII_BMCR
, reg
| BMCR_ISO
);
346 mii_phy_down(struct mii_softc
*sc
)
349 if (sc
->mii_flags
& MIIF_DOINGAUTO
) {
350 sc
->mii_flags
&= ~MIIF_DOINGAUTO
;
351 callout_stop(&sc
->mii_nway_ch
);
356 mii_phy_status(struct mii_softc
*sc
)
363 mii_phy_update(struct mii_softc
*sc
, int cmd
)
365 struct mii_data
*mii
= sc
->mii_pdata
;
367 if (sc
->mii_media_active
!= mii
->mii_media_active
||
368 sc
->mii_media_status
!= mii
->mii_media_status
||
369 cmd
== MII_MEDIACHG
) {
370 mii_phy_statusmsg(sc
);
371 (*mii
->mii_statchg
)(device_parent(sc
->mii_dev
));
372 sc
->mii_media_active
= mii
->mii_media_active
;
373 sc
->mii_media_status
= mii
->mii_media_status
;
378 mii_phy_statusmsg(struct mii_softc
*sc
)
380 struct mii_data
*mii
= sc
->mii_pdata
;
381 struct ifnet
*ifp
= mii
->mii_ifp
;
385 if (mii
->mii_media_status
& IFM_AVALID
) {
386 if (mii
->mii_media_status
& IFM_ACTIVE
)
387 if_link_state_change(ifp
, LINK_STATE_UP
);
389 if_link_state_change(ifp
, LINK_STATE_DOWN
);
391 if_link_state_change(ifp
, LINK_STATE_UNKNOWN
);
394 ifp
->if_baudrate
= ifmedia_baudrate(mii
->mii_media_active
);
398 * Initialize generic PHY media based on BMSR, called when a PHY is
399 * attached. We expect to be set up to print a comma-separated list
400 * of media names. Does not print a newline.
403 mii_phy_add_media(struct mii_softc
*sc
)
405 struct mii_data
*mii
= sc
->mii_pdata
;
406 device_t self
= sc
->mii_dev
;
407 const char *sep
= "";
410 #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
411 #define PRINT(n) aprint_normal("%s%s", sep, (n)); sep = ", "
413 if ((sc
->mii_flags
& MIIF_NOISOLATE
) == 0)
414 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_NONE
, 0, sc
->mii_inst
),
418 * There are different interpretations for the bits in
419 * HomePNA PHYs. And there is really only one media type
422 if (sc
->mii_flags
& MIIF_IS_HPNA
) {
423 if (sc
->mii_capabilities
& BMSR_10THDX
) {
424 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_HPNA_1
, 0,
432 if (sc
->mii_capabilities
& BMSR_10THDX
) {
433 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_10_T
, 0, sc
->mii_inst
),
437 if (sc
->mii_capabilities
& BMSR_10TFDX
) {
438 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_10_T
, IFM_FDX
, sc
->mii_inst
),
440 PRINT("10baseT-FDX");
443 if (sc
->mii_capabilities
& BMSR_100TXHDX
) {
444 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_100_TX
, 0, sc
->mii_inst
),
448 if (sc
->mii_capabilities
& BMSR_100TXFDX
) {
449 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_100_TX
, IFM_FDX
, sc
->mii_inst
),
450 MII_MEDIA_100_TX_FDX
);
451 PRINT("100baseTX-FDX");
454 if (sc
->mii_capabilities
& BMSR_100T4
) {
455 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_100_T4
, 0, sc
->mii_inst
),
460 if (sc
->mii_extcapabilities
& EXTSR_MEDIAMASK
) {
462 * XXX Right now only handle 1000SX and 1000TX. Need
463 * XXX to handle 1000LX and 1000CX some how.
465 * Note since it can take 5 seconds to auto-negotiate
466 * a gigabit link, we make anegticks 10 seconds for
467 * all the gigabit media types.
469 if (sc
->mii_extcapabilities
& EXTSR_1000XHDX
) {
470 sc
->mii_anegticks
= MII_ANEGTICKS_GIGE
;
471 sc
->mii_flags
|= MIIF_IS_1000X
;
472 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_1000_SX
, 0,
473 sc
->mii_inst
), MII_MEDIA_1000_X
);
476 if (sc
->mii_extcapabilities
& EXTSR_1000XFDX
) {
477 sc
->mii_anegticks
= MII_ANEGTICKS_GIGE
;
478 sc
->mii_flags
|= MIIF_IS_1000X
;
479 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_1000_SX
, IFM_FDX
,
480 sc
->mii_inst
), MII_MEDIA_1000_X_FDX
);
481 PRINT("1000baseSX-FDX");
486 * 1000baseT media needs to be able to manipulate
487 * master/slave mode. We set IFM_ETH_MASTER in
488 * the "don't care mask" and filter it out when
491 * All 1000baseT PHYs have a 1000baseT control register.
493 if (sc
->mii_extcapabilities
& EXTSR_1000THDX
) {
494 sc
->mii_anegticks
= MII_ANEGTICKS_GIGE
;
495 sc
->mii_flags
|= MIIF_HAVE_GTCR
;
496 mii
->mii_media
.ifm_mask
|= IFM_ETH_MASTER
;
497 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_1000_T
, 0,
498 sc
->mii_inst
), MII_MEDIA_1000_T
);
501 if (sc
->mii_extcapabilities
& EXTSR_1000TFDX
) {
502 sc
->mii_anegticks
= MII_ANEGTICKS_GIGE
;
503 sc
->mii_flags
|= MIIF_HAVE_GTCR
;
504 mii
->mii_media
.ifm_mask
|= IFM_ETH_MASTER
;
505 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_1000_T
, IFM_FDX
,
506 sc
->mii_inst
), MII_MEDIA_1000_T_FDX
);
507 PRINT("1000baseT-FDX");
512 if (sc
->mii_capabilities
& BMSR_ANEG
) {
513 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_AUTO
, 0, sc
->mii_inst
),
514 MII_NMEDIA
); /* intentionally invalid index */
519 if (fdx
!= 0 && (sc
->mii_flags
& MIIF_DOPAUSE
))
520 mii
->mii_media
.ifm_mask
|= IFM_ETH_FMASK
;
522 if (!pmf_device_register(self
, NULL
, mii_phy_resume
)) {
524 aprint_error_dev(self
, "couldn't establish power handler");
529 mii_phy_delete_media(struct mii_softc
*sc
)
531 struct mii_data
*mii
= sc
->mii_pdata
;
533 ifmedia_delete_instance(&mii
->mii_media
, sc
->mii_inst
);
537 mii_phy_activate(device_t self
, enum devact act
)
540 case DVACT_DEACTIVATE
:
541 /* XXX Invalidate parent's media setting? */
550 mii_phy_detach(device_t self
, int flags
)
552 struct mii_softc
*sc
= device_private(self
);
554 /* XXX Invalidate parent's media setting? */
556 if (sc
->mii_flags
& MIIF_DOINGAUTO
)
557 callout_stop(&sc
->mii_nway_ch
);
559 callout_destroy(&sc
->mii_nway_ch
);
561 mii_phy_delete_media(sc
);
562 LIST_REMOVE(sc
, mii_list
);
567 const struct mii_phydesc
*
568 mii_phy_match(const struct mii_attach_args
*ma
, const struct mii_phydesc
*mpd
)
571 for (; mpd
->mpd_name
!= NULL
; mpd
++) {
572 if (MII_OUI(ma
->mii_id1
, ma
->mii_id2
) == mpd
->mpd_oui
&&
573 MII_MODEL(ma
->mii_id2
) == mpd
->mpd_model
)
580 * Return the flow control status flag from MII_ANAR & MII_ANLPAR.
583 mii_phy_flowstatus(struct mii_softc
*sc
)
587 if ((sc
->mii_flags
& MIIF_DOPAUSE
) == 0)
590 anar
= PHY_READ(sc
, MII_ANAR
);
591 anlpar
= PHY_READ(sc
, MII_ANLPAR
);
593 if ((anar
& ANAR_X_PAUSE_SYM
) & (anlpar
& ANLPAR_X_PAUSE_SYM
))
594 return (IFM_FLOW
|IFM_ETH_TXPAUSE
|IFM_ETH_RXPAUSE
);
596 if ((anar
& ANAR_X_PAUSE_SYM
) == 0) {
597 if ((anar
& ANAR_X_PAUSE_ASYM
) &&
599 ANLPAR_X_PAUSE_TOWARDS
) == ANLPAR_X_PAUSE_TOWARDS
))
600 return (IFM_FLOW
|IFM_ETH_TXPAUSE
);
605 if ((anar
& ANAR_X_PAUSE_ASYM
) == 0) {
606 if (anlpar
& ANLPAR_X_PAUSE_SYM
)
607 return (IFM_FLOW
|IFM_ETH_TXPAUSE
|IFM_ETH_RXPAUSE
);
612 switch ((anlpar
& ANLPAR_X_PAUSE_TOWARDS
)) {
613 case ANLPAR_X_PAUSE_NONE
:
616 case ANLPAR_X_PAUSE_ASYM
:
617 return (IFM_FLOW
|IFM_ETH_RXPAUSE
);
620 return (IFM_FLOW
|IFM_ETH_RXPAUSE
|IFM_ETH_TXPAUSE
);
626 mii_phy_resume(device_t dv
, pmf_qual_t qual
)
628 struct mii_softc
*sc
= device_private(dv
);
631 return PHY_SERVICE(sc
, sc
->mii_pdata
, MII_MEDIACHG
) == 0;
636 * Given an ifmedia word, return the corresponding ANAR value.
643 switch (media
& (IFM_TMASK
|IFM_NMASK
|IFM_FDX
)) {
644 case IFM_ETHER
|IFM_10_T
:
645 rv
= ANAR_10
|ANAR_CSMA
;
647 case IFM_ETHER
|IFM_10_T
|IFM_FDX
:
648 rv
= ANAR_10_FD
|ANAR_CSMA
;
650 case IFM_ETHER
|IFM_100_TX
:
651 rv
= ANAR_TX
|ANAR_CSMA
;
653 case IFM_ETHER
|IFM_100_TX
|IFM_FDX
:
654 rv
= ANAR_TX_FD
|ANAR_CSMA
;
656 case IFM_ETHER
|IFM_100_T4
:
657 rv
= ANAR_T4
|ANAR_CSMA
;