3 mii.c: MII interface library
5 Maintained by Jeff Garzik <jgarzik@pobox.com>
6 Copyright 2001,2002 Jeff Garzik
8 Various code came from myson803.c and other files by
9 Donald Becker. Copyright:
11 Written 1998-2002 by Donald Becker.
13 This software may be used and distributed according
14 to the terms of the GNU General Public License (GPL),
15 incorporated herein by reference. Drivers based on
16 or derived from this code fall under the GPL and must
17 retain the authorship, copyright and license notice.
18 This file is not a complete program and may only be
19 used when the entire operating system is licensed
22 The author may be reached as becker@scyld.com, or C/O
23 Scyld Computing Corporation
24 410 Severn Ave., Suite 210
30 #include <linux/kernel.h>
31 #include <linux/module.h>
32 #include <linux/netdevice.h>
33 #include <linux/ethtool.h>
34 #include <linux/mii.h>
36 static u32
mii_get_an(struct mii_if_info
*mii
, u16 addr
)
40 advert
= mii
->mdio_read(mii
->dev
, mii
->phy_id
, addr
);
42 return mii_lpa_to_ethtool_lpa_t(advert
);
46 * mii_ethtool_gset - get settings that are specified in @ecmd
48 * @ecmd: requested ethtool_cmd
50 * The @ecmd parameter is expected to have been cleared before calling
53 * Returns 0 for success, negative on error.
55 int mii_ethtool_gset(struct mii_if_info
*mii
, struct ethtool_cmd
*ecmd
)
57 struct net_device
*dev
= mii
->dev
;
58 u16 bmcr
, bmsr
, ctrl1000
= 0, stat1000
= 0;
62 (SUPPORTED_10baseT_Half
| SUPPORTED_10baseT_Full
|
63 SUPPORTED_100baseT_Half
| SUPPORTED_100baseT_Full
|
64 SUPPORTED_Autoneg
| SUPPORTED_TP
| SUPPORTED_MII
);
65 if (mii
->supports_gmii
)
66 ecmd
->supported
|= SUPPORTED_1000baseT_Half
|
67 SUPPORTED_1000baseT_Full
;
69 /* only supports twisted-pair */
70 ecmd
->port
= PORT_MII
;
72 /* only supports internal transceiver */
73 ecmd
->transceiver
= XCVR_INTERNAL
;
75 /* this isn't fully supported at higher layers */
76 ecmd
->phy_address
= mii
->phy_id
;
77 ecmd
->mdio_support
= ETH_MDIO_SUPPORTS_C22
;
79 ecmd
->advertising
= ADVERTISED_TP
| ADVERTISED_MII
;
81 bmcr
= mii
->mdio_read(dev
, mii
->phy_id
, MII_BMCR
);
82 bmsr
= mii
->mdio_read(dev
, mii
->phy_id
, MII_BMSR
);
83 if (mii
->supports_gmii
) {
84 ctrl1000
= mii
->mdio_read(dev
, mii
->phy_id
, MII_CTRL1000
);
85 stat1000
= mii
->mdio_read(dev
, mii
->phy_id
, MII_STAT1000
);
87 if (bmcr
& BMCR_ANENABLE
) {
88 ecmd
->advertising
|= ADVERTISED_Autoneg
;
89 ecmd
->autoneg
= AUTONEG_ENABLE
;
91 ecmd
->advertising
|= mii_get_an(mii
, MII_ADVERTISE
);
92 if (mii
->supports_gmii
)
94 mii_ctrl1000_to_ethtool_adv_t(ctrl1000
);
96 if (bmsr
& BMSR_ANEGCOMPLETE
) {
97 ecmd
->lp_advertising
= mii_get_an(mii
, MII_LPA
);
98 ecmd
->lp_advertising
|=
99 mii_stat1000_to_ethtool_lpa_t(stat1000
);
101 ecmd
->lp_advertising
= 0;
104 nego
= ecmd
->advertising
& ecmd
->lp_advertising
;
106 if (nego
& (ADVERTISED_1000baseT_Full
|
107 ADVERTISED_1000baseT_Half
)) {
108 ethtool_cmd_speed_set(ecmd
, SPEED_1000
);
109 ecmd
->duplex
= !!(nego
& ADVERTISED_1000baseT_Full
);
110 } else if (nego
& (ADVERTISED_100baseT_Full
|
111 ADVERTISED_100baseT_Half
)) {
112 ethtool_cmd_speed_set(ecmd
, SPEED_100
);
113 ecmd
->duplex
= !!(nego
& ADVERTISED_100baseT_Full
);
115 ethtool_cmd_speed_set(ecmd
, SPEED_10
);
116 ecmd
->duplex
= !!(nego
& ADVERTISED_10baseT_Full
);
119 ecmd
->autoneg
= AUTONEG_DISABLE
;
121 ethtool_cmd_speed_set(ecmd
,
122 ((bmcr
& BMCR_SPEED1000
&&
123 (bmcr
& BMCR_SPEED100
) == 0) ?
125 ((bmcr
& BMCR_SPEED100
) ?
126 SPEED_100
: SPEED_10
)));
127 ecmd
->duplex
= (bmcr
& BMCR_FULLDPLX
) ? DUPLEX_FULL
: DUPLEX_HALF
;
130 mii
->full_duplex
= ecmd
->duplex
;
132 /* ignore maxtxpkt, maxrxpkt for now */
138 * mii_ethtool_sset - set settings that are specified in @ecmd
139 * @mii: MII interface
140 * @ecmd: requested ethtool_cmd
142 * Returns 0 for success, negative on error.
144 int mii_ethtool_sset(struct mii_if_info
*mii
, struct ethtool_cmd
*ecmd
)
146 struct net_device
*dev
= mii
->dev
;
147 u32 speed
= ethtool_cmd_speed(ecmd
);
149 if (speed
!= SPEED_10
&&
150 speed
!= SPEED_100
&&
153 if (ecmd
->duplex
!= DUPLEX_HALF
&& ecmd
->duplex
!= DUPLEX_FULL
)
155 if (ecmd
->port
!= PORT_MII
)
157 if (ecmd
->transceiver
!= XCVR_INTERNAL
)
159 if (ecmd
->phy_address
!= mii
->phy_id
)
161 if (ecmd
->autoneg
!= AUTONEG_DISABLE
&& ecmd
->autoneg
!= AUTONEG_ENABLE
)
163 if ((speed
== SPEED_1000
) && (!mii
->supports_gmii
))
166 /* ignore supported, maxtxpkt, maxrxpkt */
168 if (ecmd
->autoneg
== AUTONEG_ENABLE
) {
169 u32 bmcr
, advert
, tmp
;
170 u32 advert2
= 0, tmp2
= 0;
172 if ((ecmd
->advertising
& (ADVERTISED_10baseT_Half
|
173 ADVERTISED_10baseT_Full
|
174 ADVERTISED_100baseT_Half
|
175 ADVERTISED_100baseT_Full
|
176 ADVERTISED_1000baseT_Half
|
177 ADVERTISED_1000baseT_Full
)) == 0)
180 /* advertise only what has been requested */
181 advert
= mii
->mdio_read(dev
, mii
->phy_id
, MII_ADVERTISE
);
182 tmp
= advert
& ~(ADVERTISE_ALL
| ADVERTISE_100BASE4
);
183 if (mii
->supports_gmii
) {
184 advert2
= mii
->mdio_read(dev
, mii
->phy_id
, MII_CTRL1000
);
185 tmp2
= advert2
& ~(ADVERTISE_1000HALF
| ADVERTISE_1000FULL
);
187 tmp
|= ethtool_adv_to_mii_adv_t(ecmd
->advertising
);
189 if (mii
->supports_gmii
)
191 ethtool_adv_to_mii_ctrl1000_t(ecmd
->advertising
);
193 mii
->mdio_write(dev
, mii
->phy_id
, MII_ADVERTISE
, tmp
);
194 mii
->advertising
= tmp
;
196 if ((mii
->supports_gmii
) && (advert2
!= tmp2
))
197 mii
->mdio_write(dev
, mii
->phy_id
, MII_CTRL1000
, tmp2
);
199 /* turn on autonegotiation, and force a renegotiate */
200 bmcr
= mii
->mdio_read(dev
, mii
->phy_id
, MII_BMCR
);
201 bmcr
|= (BMCR_ANENABLE
| BMCR_ANRESTART
);
202 mii
->mdio_write(dev
, mii
->phy_id
, MII_BMCR
, bmcr
);
204 mii
->force_media
= 0;
208 /* turn off auto negotiation, set speed and duplexity */
209 bmcr
= mii
->mdio_read(dev
, mii
->phy_id
, MII_BMCR
);
210 tmp
= bmcr
& ~(BMCR_ANENABLE
| BMCR_SPEED100
|
211 BMCR_SPEED1000
| BMCR_FULLDPLX
);
212 if (speed
== SPEED_1000
)
213 tmp
|= BMCR_SPEED1000
;
214 else if (speed
== SPEED_100
)
215 tmp
|= BMCR_SPEED100
;
216 if (ecmd
->duplex
== DUPLEX_FULL
) {
217 tmp
|= BMCR_FULLDPLX
;
218 mii
->full_duplex
= 1;
220 mii
->full_duplex
= 0;
222 mii
->mdio_write(dev
, mii
->phy_id
, MII_BMCR
, tmp
);
224 mii
->force_media
= 1;
230 * mii_check_gmii_support - check if the MII supports Gb interfaces
231 * @mii: the MII interface
233 int mii_check_gmii_support(struct mii_if_info
*mii
)
237 reg
= mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_BMSR
);
238 if (reg
& BMSR_ESTATEN
) {
239 reg
= mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_ESTATUS
);
240 if (reg
& (ESTATUS_1000_TFULL
| ESTATUS_1000_THALF
))
248 * mii_link_ok - is link status up/ok
249 * @mii: the MII interface
251 * Returns 1 if the MII reports link status up/ok, 0 otherwise.
253 int mii_link_ok (struct mii_if_info
*mii
)
255 /* first, a dummy read, needed to latch some MII phys */
256 mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_BMSR
);
257 if (mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_BMSR
) & BMSR_LSTATUS
)
263 * mii_nway_restart - restart NWay (autonegotiation) for this interface
264 * @mii: the MII interface
266 * Returns 0 on success, negative on error.
268 int mii_nway_restart (struct mii_if_info
*mii
)
273 /* if autoneg is off, it's an error */
274 bmcr
= mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_BMCR
);
276 if (bmcr
& BMCR_ANENABLE
) {
277 bmcr
|= BMCR_ANRESTART
;
278 mii
->mdio_write(mii
->dev
, mii
->phy_id
, MII_BMCR
, bmcr
);
286 * mii_check_link - check MII link status
287 * @mii: MII interface
289 * If the link status changed (previous != current), call
290 * netif_carrier_on() if current link status is Up or call
291 * netif_carrier_off() if current link status is Down.
293 void mii_check_link (struct mii_if_info
*mii
)
295 int cur_link
= mii_link_ok(mii
);
296 int prev_link
= netif_carrier_ok(mii
->dev
);
298 if (cur_link
&& !prev_link
)
299 netif_carrier_on(mii
->dev
);
300 else if (prev_link
&& !cur_link
)
301 netif_carrier_off(mii
->dev
);
305 * mii_check_media - check the MII interface for a carrier/speed/duplex change
306 * @mii: the MII interface
307 * @ok_to_print: OK to print link up/down messages
308 * @init_media: OK to save duplex mode in @mii
310 * Returns 1 if the duplex mode changed, 0 if not.
311 * If the media type is forced, always returns 0.
313 unsigned int mii_check_media (struct mii_if_info
*mii
,
314 unsigned int ok_to_print
,
315 unsigned int init_media
)
317 unsigned int old_carrier
, new_carrier
;
318 int advertise
, lpa
, media
, duplex
;
321 /* check current and old link status */
322 old_carrier
= netif_carrier_ok(mii
->dev
) ? 1 : 0;
323 new_carrier
= (unsigned int) mii_link_ok(mii
);
325 /* if carrier state did not change, this is a "bounce",
326 * just exit as everything is already set correctly
328 if ((!init_media
) && (old_carrier
== new_carrier
))
329 return 0; /* duplex did not change */
331 /* no carrier, nothing much to do */
333 netif_carrier_off(mii
->dev
);
335 netdev_info(mii
->dev
, "link down\n");
336 return 0; /* duplex did not change */
340 * we have carrier, see who's on the other end
342 netif_carrier_on(mii
->dev
);
344 if (mii
->force_media
) {
346 netdev_info(mii
->dev
, "link up\n");
347 return 0; /* duplex did not change */
350 /* get MII advertise and LPA values */
351 if ((!init_media
) && (mii
->advertising
))
352 advertise
= mii
->advertising
;
354 advertise
= mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_ADVERTISE
);
355 mii
->advertising
= advertise
;
357 lpa
= mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_LPA
);
358 if (mii
->supports_gmii
)
359 lpa2
= mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_STAT1000
);
361 /* figure out media and duplex from advertise and LPA values */
362 media
= mii_nway_result(lpa
& advertise
);
363 duplex
= (media
& ADVERTISE_FULL
) ? 1 : 0;
364 if (lpa2
& LPA_1000FULL
)
368 netdev_info(mii
->dev
, "link up, %uMbps, %s-duplex, lpa 0x%04X\n",
369 lpa2
& (LPA_1000FULL
| LPA_1000HALF
) ? 1000 :
370 media
& (ADVERTISE_100FULL
| ADVERTISE_100HALF
) ?
372 duplex
? "full" : "half",
375 if ((init_media
) || (mii
->full_duplex
!= duplex
)) {
376 mii
->full_duplex
= duplex
;
377 return 1; /* duplex changed */
380 return 0; /* duplex did not change */
384 * generic_mii_ioctl - main MII ioctl interface
385 * @mii_if: the MII interface
386 * @mii_data: MII ioctl data structure
387 * @cmd: MII ioctl command
388 * @duplex_chg_out: pointer to @duplex_changed status if there was no
391 * Returns 0 on success, negative on error.
393 int generic_mii_ioctl(struct mii_if_info
*mii_if
,
394 struct mii_ioctl_data
*mii_data
, int cmd
,
395 unsigned int *duplex_chg_out
)
398 unsigned int duplex_changed
= 0;
403 mii_data
->phy_id
&= mii_if
->phy_id_mask
;
404 mii_data
->reg_num
&= mii_if
->reg_num_mask
;
408 mii_data
->phy_id
= mii_if
->phy_id
;
413 mii_if
->mdio_read(mii_if
->dev
, mii_data
->phy_id
,
418 u16 val
= mii_data
->val_in
;
420 if (mii_data
->phy_id
== mii_if
->phy_id
) {
421 switch(mii_data
->reg_num
) {
423 unsigned int new_duplex
= 0;
424 if (val
& (BMCR_RESET
|BMCR_ANENABLE
))
425 mii_if
->force_media
= 0;
427 mii_if
->force_media
= 1;
428 if (mii_if
->force_media
&&
429 (val
& BMCR_FULLDPLX
))
431 if (mii_if
->full_duplex
!= new_duplex
) {
433 mii_if
->full_duplex
= new_duplex
;
438 mii_if
->advertising
= val
;
446 mii_if
->mdio_write(mii_if
->dev
, mii_data
->phy_id
,
447 mii_data
->reg_num
, val
);
456 if ((rc
== 0) && (duplex_chg_out
) && (duplex_changed
))
462 MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>");
463 MODULE_DESCRIPTION ("MII hardware support library");
464 MODULE_LICENSE("GPL");
466 EXPORT_SYMBOL(mii_link_ok
);
467 EXPORT_SYMBOL(mii_nway_restart
);
468 EXPORT_SYMBOL(mii_ethtool_gset
);
469 EXPORT_SYMBOL(mii_ethtool_sset
);
470 EXPORT_SYMBOL(mii_check_link
);
471 EXPORT_SYMBOL(mii_check_media
);
472 EXPORT_SYMBOL(mii_check_gmii_support
);
473 EXPORT_SYMBOL(generic_mii_ioctl
);