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/mdio.h>
36 static u32
mii_get_an(struct mii_if_info
*mii
, u16 addr
)
41 advert
= mii
->mdio_read(mii
->dev
, mii
->phy_id
, addr
);
42 if (advert
& LPA_LPACK
)
43 result
|= ADVERTISED_Autoneg
;
44 if (advert
& ADVERTISE_10HALF
)
45 result
|= ADVERTISED_10baseT_Half
;
46 if (advert
& ADVERTISE_10FULL
)
47 result
|= ADVERTISED_10baseT_Full
;
48 if (advert
& ADVERTISE_100HALF
)
49 result
|= ADVERTISED_100baseT_Half
;
50 if (advert
& ADVERTISE_100FULL
)
51 result
|= ADVERTISED_100baseT_Full
;
57 * mii_ethtool_gset - get settings that are specified in @ecmd
59 * @ecmd: requested ethtool_cmd
61 * The @ecmd parameter is expected to have been cleared before calling
64 * Returns 0 for success, negative on error.
66 int mii_ethtool_gset(struct mii_if_info
*mii
, struct ethtool_cmd
*ecmd
)
68 struct net_device
*dev
= mii
->dev
;
69 u16 bmcr
, bmsr
, ctrl1000
= 0, stat1000
= 0;
73 (SUPPORTED_10baseT_Half
| SUPPORTED_10baseT_Full
|
74 SUPPORTED_100baseT_Half
| SUPPORTED_100baseT_Full
|
75 SUPPORTED_Autoneg
| SUPPORTED_TP
| SUPPORTED_MII
);
76 if (mii
->supports_gmii
)
77 ecmd
->supported
|= SUPPORTED_1000baseT_Half
|
78 SUPPORTED_1000baseT_Full
;
80 /* only supports twisted-pair */
81 ecmd
->port
= PORT_MII
;
83 /* only supports internal transceiver */
84 ecmd
->transceiver
= XCVR_INTERNAL
;
86 /* this isn't fully supported at higher layers */
87 ecmd
->phy_address
= mii
->phy_id
;
88 ecmd
->mdio_support
= MDIO_SUPPORTS_C22
;
90 ecmd
->advertising
= ADVERTISED_TP
| ADVERTISED_MII
;
92 bmcr
= mii
->mdio_read(dev
, mii
->phy_id
, MII_BMCR
);
93 bmsr
= mii
->mdio_read(dev
, mii
->phy_id
, MII_BMSR
);
94 if (mii
->supports_gmii
) {
95 ctrl1000
= mii
->mdio_read(dev
, mii
->phy_id
, MII_CTRL1000
);
96 stat1000
= mii
->mdio_read(dev
, mii
->phy_id
, MII_STAT1000
);
98 if (bmcr
& BMCR_ANENABLE
) {
99 ecmd
->advertising
|= ADVERTISED_Autoneg
;
100 ecmd
->autoneg
= AUTONEG_ENABLE
;
102 ecmd
->advertising
|= mii_get_an(mii
, MII_ADVERTISE
);
103 if (ctrl1000
& ADVERTISE_1000HALF
)
104 ecmd
->advertising
|= ADVERTISED_1000baseT_Half
;
105 if (ctrl1000
& ADVERTISE_1000FULL
)
106 ecmd
->advertising
|= ADVERTISED_1000baseT_Full
;
108 if (bmsr
& BMSR_ANEGCOMPLETE
) {
109 ecmd
->lp_advertising
= mii_get_an(mii
, MII_LPA
);
110 if (stat1000
& LPA_1000HALF
)
111 ecmd
->lp_advertising
|=
112 ADVERTISED_1000baseT_Half
;
113 if (stat1000
& LPA_1000FULL
)
114 ecmd
->lp_advertising
|=
115 ADVERTISED_1000baseT_Full
;
117 ecmd
->lp_advertising
= 0;
120 nego
= ecmd
->advertising
& ecmd
->lp_advertising
;
122 if (nego
& (ADVERTISED_1000baseT_Full
|
123 ADVERTISED_1000baseT_Half
)) {
124 ethtool_cmd_speed_set(ecmd
, SPEED_1000
);
125 ecmd
->duplex
= !!(nego
& ADVERTISED_1000baseT_Full
);
126 } else if (nego
& (ADVERTISED_100baseT_Full
|
127 ADVERTISED_100baseT_Half
)) {
128 ethtool_cmd_speed_set(ecmd
, SPEED_100
);
129 ecmd
->duplex
= !!(nego
& ADVERTISED_100baseT_Full
);
131 ethtool_cmd_speed_set(ecmd
, SPEED_10
);
132 ecmd
->duplex
= !!(nego
& ADVERTISED_10baseT_Full
);
135 ecmd
->autoneg
= AUTONEG_DISABLE
;
137 ethtool_cmd_speed_set(ecmd
,
138 ((bmcr
& BMCR_SPEED1000
&&
139 (bmcr
& BMCR_SPEED100
) == 0) ?
141 ((bmcr
& BMCR_SPEED100
) ?
142 SPEED_100
: SPEED_10
)));
143 ecmd
->duplex
= (bmcr
& BMCR_FULLDPLX
) ? DUPLEX_FULL
: DUPLEX_HALF
;
146 mii
->full_duplex
= ecmd
->duplex
;
148 /* ignore maxtxpkt, maxrxpkt for now */
154 * mii_ethtool_sset - set settings that are specified in @ecmd
155 * @mii: MII interface
156 * @ecmd: requested ethtool_cmd
158 * Returns 0 for success, negative on error.
160 int mii_ethtool_sset(struct mii_if_info
*mii
, struct ethtool_cmd
*ecmd
)
162 struct net_device
*dev
= mii
->dev
;
163 u32 speed
= ethtool_cmd_speed(ecmd
);
165 if (speed
!= SPEED_10
&&
166 speed
!= SPEED_100
&&
169 if (ecmd
->duplex
!= DUPLEX_HALF
&& ecmd
->duplex
!= DUPLEX_FULL
)
171 if (ecmd
->port
!= PORT_MII
)
173 if (ecmd
->transceiver
!= XCVR_INTERNAL
)
175 if (ecmd
->phy_address
!= mii
->phy_id
)
177 if (ecmd
->autoneg
!= AUTONEG_DISABLE
&& ecmd
->autoneg
!= AUTONEG_ENABLE
)
179 if ((speed
== SPEED_1000
) && (!mii
->supports_gmii
))
182 /* ignore supported, maxtxpkt, maxrxpkt */
184 if (ecmd
->autoneg
== AUTONEG_ENABLE
) {
185 u32 bmcr
, advert
, tmp
;
186 u32 advert2
= 0, tmp2
= 0;
188 if ((ecmd
->advertising
& (ADVERTISED_10baseT_Half
|
189 ADVERTISED_10baseT_Full
|
190 ADVERTISED_100baseT_Half
|
191 ADVERTISED_100baseT_Full
|
192 ADVERTISED_1000baseT_Half
|
193 ADVERTISED_1000baseT_Full
)) == 0)
196 /* advertise only what has been requested */
197 advert
= mii
->mdio_read(dev
, mii
->phy_id
, MII_ADVERTISE
);
198 tmp
= advert
& ~(ADVERTISE_ALL
| ADVERTISE_100BASE4
);
199 if (mii
->supports_gmii
) {
200 advert2
= mii
->mdio_read(dev
, mii
->phy_id
, MII_CTRL1000
);
201 tmp2
= advert2
& ~(ADVERTISE_1000HALF
| ADVERTISE_1000FULL
);
203 if (ecmd
->advertising
& ADVERTISED_10baseT_Half
)
204 tmp
|= ADVERTISE_10HALF
;
205 if (ecmd
->advertising
& ADVERTISED_10baseT_Full
)
206 tmp
|= ADVERTISE_10FULL
;
207 if (ecmd
->advertising
& ADVERTISED_100baseT_Half
)
208 tmp
|= ADVERTISE_100HALF
;
209 if (ecmd
->advertising
& ADVERTISED_100baseT_Full
)
210 tmp
|= ADVERTISE_100FULL
;
211 if (mii
->supports_gmii
) {
212 if (ecmd
->advertising
& ADVERTISED_1000baseT_Half
)
213 tmp2
|= ADVERTISE_1000HALF
;
214 if (ecmd
->advertising
& ADVERTISED_1000baseT_Full
)
215 tmp2
|= ADVERTISE_1000FULL
;
218 mii
->mdio_write(dev
, mii
->phy_id
, MII_ADVERTISE
, tmp
);
219 mii
->advertising
= tmp
;
221 if ((mii
->supports_gmii
) && (advert2
!= tmp2
))
222 mii
->mdio_write(dev
, mii
->phy_id
, MII_CTRL1000
, tmp2
);
224 /* turn on autonegotiation, and force a renegotiate */
225 bmcr
= mii
->mdio_read(dev
, mii
->phy_id
, MII_BMCR
);
226 bmcr
|= (BMCR_ANENABLE
| BMCR_ANRESTART
);
227 mii
->mdio_write(dev
, mii
->phy_id
, MII_BMCR
, bmcr
);
229 mii
->force_media
= 0;
233 /* turn off auto negotiation, set speed and duplexity */
234 bmcr
= mii
->mdio_read(dev
, mii
->phy_id
, MII_BMCR
);
235 tmp
= bmcr
& ~(BMCR_ANENABLE
| BMCR_SPEED100
|
236 BMCR_SPEED1000
| BMCR_FULLDPLX
);
237 if (speed
== SPEED_1000
)
238 tmp
|= BMCR_SPEED1000
;
239 else if (speed
== SPEED_100
)
240 tmp
|= BMCR_SPEED100
;
241 if (ecmd
->duplex
== DUPLEX_FULL
) {
242 tmp
|= BMCR_FULLDPLX
;
243 mii
->full_duplex
= 1;
245 mii
->full_duplex
= 0;
247 mii
->mdio_write(dev
, mii
->phy_id
, MII_BMCR
, tmp
);
249 mii
->force_media
= 1;
255 * mii_check_gmii_support - check if the MII supports Gb interfaces
256 * @mii: the MII interface
258 int mii_check_gmii_support(struct mii_if_info
*mii
)
262 reg
= mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_BMSR
);
263 if (reg
& BMSR_ESTATEN
) {
264 reg
= mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_ESTATUS
);
265 if (reg
& (ESTATUS_1000_TFULL
| ESTATUS_1000_THALF
))
273 * mii_link_ok - is link status up/ok
274 * @mii: the MII interface
276 * Returns 1 if the MII reports link status up/ok, 0 otherwise.
278 int mii_link_ok (struct mii_if_info
*mii
)
280 /* first, a dummy read, needed to latch some MII phys */
281 mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_BMSR
);
282 if (mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_BMSR
) & BMSR_LSTATUS
)
288 * mii_nway_restart - restart NWay (autonegotiation) for this interface
289 * @mii: the MII interface
291 * Returns 0 on success, negative on error.
293 int mii_nway_restart (struct mii_if_info
*mii
)
298 /* if autoneg is off, it's an error */
299 bmcr
= mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_BMCR
);
301 if (bmcr
& BMCR_ANENABLE
) {
302 bmcr
|= BMCR_ANRESTART
;
303 mii
->mdio_write(mii
->dev
, mii
->phy_id
, MII_BMCR
, bmcr
);
311 * mii_check_link - check MII link status
312 * @mii: MII interface
314 * If the link status changed (previous != current), call
315 * netif_carrier_on() if current link status is Up or call
316 * netif_carrier_off() if current link status is Down.
318 void mii_check_link (struct mii_if_info
*mii
)
320 int cur_link
= mii_link_ok(mii
);
321 int prev_link
= netif_carrier_ok(mii
->dev
);
323 if (cur_link
&& !prev_link
)
324 netif_carrier_on(mii
->dev
);
325 else if (prev_link
&& !cur_link
)
326 netif_carrier_off(mii
->dev
);
330 * mii_check_media - check the MII interface for a duplex change
331 * @mii: the MII interface
332 * @ok_to_print: OK to print link up/down messages
333 * @init_media: OK to save duplex mode in @mii
335 * Returns 1 if the duplex mode changed, 0 if not.
336 * If the media type is forced, always returns 0.
338 unsigned int mii_check_media (struct mii_if_info
*mii
,
339 unsigned int ok_to_print
,
340 unsigned int init_media
)
342 unsigned int old_carrier
, new_carrier
;
343 int advertise
, lpa
, media
, duplex
;
346 /* if forced media, go no further */
347 if (mii
->force_media
)
348 return 0; /* duplex did not change */
350 /* check current and old link status */
351 old_carrier
= netif_carrier_ok(mii
->dev
) ? 1 : 0;
352 new_carrier
= (unsigned int) mii_link_ok(mii
);
354 /* if carrier state did not change, this is a "bounce",
355 * just exit as everything is already set correctly
357 if ((!init_media
) && (old_carrier
== new_carrier
))
358 return 0; /* duplex did not change */
360 /* no carrier, nothing much to do */
362 netif_carrier_off(mii
->dev
);
364 netdev_info(mii
->dev
, "link down\n");
365 return 0; /* duplex did not change */
369 * we have carrier, see who's on the other end
371 netif_carrier_on(mii
->dev
);
373 /* get MII advertise and LPA values */
374 if ((!init_media
) && (mii
->advertising
))
375 advertise
= mii
->advertising
;
377 advertise
= mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_ADVERTISE
);
378 mii
->advertising
= advertise
;
380 lpa
= mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_LPA
);
381 if (mii
->supports_gmii
)
382 lpa2
= mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_STAT1000
);
384 /* figure out media and duplex from advertise and LPA values */
385 media
= mii_nway_result(lpa
& advertise
);
386 duplex
= (media
& ADVERTISE_FULL
) ? 1 : 0;
387 if (lpa2
& LPA_1000FULL
)
391 netdev_info(mii
->dev
, "link up, %uMbps, %s-duplex, lpa 0x%04X\n",
392 lpa2
& (LPA_1000FULL
| LPA_1000HALF
) ? 1000 :
393 media
& (ADVERTISE_100FULL
| ADVERTISE_100HALF
) ?
395 duplex
? "full" : "half",
398 if ((init_media
) || (mii
->full_duplex
!= duplex
)) {
399 mii
->full_duplex
= duplex
;
400 return 1; /* duplex changed */
403 return 0; /* duplex did not change */
407 * generic_mii_ioctl - main MII ioctl interface
408 * @mii_if: the MII interface
409 * @mii_data: MII ioctl data structure
410 * @cmd: MII ioctl command
411 * @duplex_chg_out: pointer to @duplex_changed status if there was no
414 * Returns 0 on success, negative on error.
416 int generic_mii_ioctl(struct mii_if_info
*mii_if
,
417 struct mii_ioctl_data
*mii_data
, int cmd
,
418 unsigned int *duplex_chg_out
)
421 unsigned int duplex_changed
= 0;
426 mii_data
->phy_id
&= mii_if
->phy_id_mask
;
427 mii_data
->reg_num
&= mii_if
->reg_num_mask
;
431 mii_data
->phy_id
= mii_if
->phy_id
;
436 mii_if
->mdio_read(mii_if
->dev
, mii_data
->phy_id
,
441 u16 val
= mii_data
->val_in
;
443 if (mii_data
->phy_id
== mii_if
->phy_id
) {
444 switch(mii_data
->reg_num
) {
446 unsigned int new_duplex
= 0;
447 if (val
& (BMCR_RESET
|BMCR_ANENABLE
))
448 mii_if
->force_media
= 0;
450 mii_if
->force_media
= 1;
451 if (mii_if
->force_media
&&
452 (val
& BMCR_FULLDPLX
))
454 if (mii_if
->full_duplex
!= new_duplex
) {
456 mii_if
->full_duplex
= new_duplex
;
461 mii_if
->advertising
= val
;
469 mii_if
->mdio_write(mii_if
->dev
, mii_data
->phy_id
,
470 mii_data
->reg_num
, val
);
479 if ((rc
== 0) && (duplex_chg_out
) && (duplex_changed
))
485 MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>");
486 MODULE_DESCRIPTION ("MII hardware support library");
487 MODULE_LICENSE("GPL");
489 EXPORT_SYMBOL(mii_link_ok
);
490 EXPORT_SYMBOL(mii_nway_restart
);
491 EXPORT_SYMBOL(mii_ethtool_gset
);
492 EXPORT_SYMBOL(mii_ethtool_sset
);
493 EXPORT_SYMBOL(mii_check_link
);
494 EXPORT_SYMBOL(mii_check_media
);
495 EXPORT_SYMBOL(mii_check_gmii_support
);
496 EXPORT_SYMBOL(generic_mii_ioctl
);