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
;
52 if (advert
& ADVERTISE_PAUSE_CAP
)
53 result
|= ADVERTISED_Pause
;
54 if (advert
& ADVERTISE_PAUSE_ASYM
)
55 result
|= ADVERTISED_Asym_Pause
;
61 * mii_ethtool_gset - get settings that are specified in @ecmd
63 * @ecmd: requested ethtool_cmd
65 * The @ecmd parameter is expected to have been cleared before calling
68 * Returns 0 for success, negative on error.
70 int mii_ethtool_gset(struct mii_if_info
*mii
, struct ethtool_cmd
*ecmd
)
72 struct net_device
*dev
= mii
->dev
;
73 u16 bmcr
, bmsr
, ctrl1000
= 0, stat1000
= 0;
77 (SUPPORTED_10baseT_Half
| SUPPORTED_10baseT_Full
|
78 SUPPORTED_100baseT_Half
| SUPPORTED_100baseT_Full
|
79 SUPPORTED_Autoneg
| SUPPORTED_TP
| SUPPORTED_MII
);
80 if (mii
->supports_gmii
)
81 ecmd
->supported
|= SUPPORTED_1000baseT_Half
|
82 SUPPORTED_1000baseT_Full
;
84 /* only supports twisted-pair */
85 ecmd
->port
= PORT_MII
;
87 /* only supports internal transceiver */
88 ecmd
->transceiver
= XCVR_INTERNAL
;
90 /* this isn't fully supported at higher layers */
91 ecmd
->phy_address
= mii
->phy_id
;
92 ecmd
->mdio_support
= MDIO_SUPPORTS_C22
;
94 ecmd
->advertising
= ADVERTISED_TP
| ADVERTISED_MII
;
96 bmcr
= mii
->mdio_read(dev
, mii
->phy_id
, MII_BMCR
);
97 bmsr
= mii
->mdio_read(dev
, mii
->phy_id
, MII_BMSR
);
98 if (mii
->supports_gmii
) {
99 ctrl1000
= mii
->mdio_read(dev
, mii
->phy_id
, MII_CTRL1000
);
100 stat1000
= mii
->mdio_read(dev
, mii
->phy_id
, MII_STAT1000
);
102 if (bmcr
& BMCR_ANENABLE
) {
103 ecmd
->advertising
|= ADVERTISED_Autoneg
;
104 ecmd
->autoneg
= AUTONEG_ENABLE
;
106 ecmd
->advertising
|= mii_get_an(mii
, MII_ADVERTISE
);
107 if (ctrl1000
& ADVERTISE_1000HALF
)
108 ecmd
->advertising
|= ADVERTISED_1000baseT_Half
;
109 if (ctrl1000
& ADVERTISE_1000FULL
)
110 ecmd
->advertising
|= ADVERTISED_1000baseT_Full
;
112 if (bmsr
& BMSR_ANEGCOMPLETE
) {
113 ecmd
->lp_advertising
= mii_get_an(mii
, MII_LPA
);
114 if (stat1000
& LPA_1000HALF
)
115 ecmd
->lp_advertising
|=
116 ADVERTISED_1000baseT_Half
;
117 if (stat1000
& LPA_1000FULL
)
118 ecmd
->lp_advertising
|=
119 ADVERTISED_1000baseT_Full
;
121 ecmd
->lp_advertising
= 0;
124 nego
= ecmd
->advertising
& ecmd
->lp_advertising
;
126 if (nego
& (ADVERTISED_1000baseT_Full
|
127 ADVERTISED_1000baseT_Half
)) {
128 ethtool_cmd_speed_set(ecmd
, SPEED_1000
);
129 ecmd
->duplex
= !!(nego
& ADVERTISED_1000baseT_Full
);
130 } else if (nego
& (ADVERTISED_100baseT_Full
|
131 ADVERTISED_100baseT_Half
)) {
132 ethtool_cmd_speed_set(ecmd
, SPEED_100
);
133 ecmd
->duplex
= !!(nego
& ADVERTISED_100baseT_Full
);
135 ethtool_cmd_speed_set(ecmd
, SPEED_10
);
136 ecmd
->duplex
= !!(nego
& ADVERTISED_10baseT_Full
);
139 ecmd
->autoneg
= AUTONEG_DISABLE
;
141 ethtool_cmd_speed_set(ecmd
,
142 ((bmcr
& BMCR_SPEED1000
&&
143 (bmcr
& BMCR_SPEED100
) == 0) ?
145 ((bmcr
& BMCR_SPEED100
) ?
146 SPEED_100
: SPEED_10
)));
147 ecmd
->duplex
= (bmcr
& BMCR_FULLDPLX
) ? DUPLEX_FULL
: DUPLEX_HALF
;
150 mii
->full_duplex
= ecmd
->duplex
;
152 /* ignore maxtxpkt, maxrxpkt for now */
158 * mii_ethtool_sset - set settings that are specified in @ecmd
159 * @mii: MII interface
160 * @ecmd: requested ethtool_cmd
162 * Returns 0 for success, negative on error.
164 int mii_ethtool_sset(struct mii_if_info
*mii
, struct ethtool_cmd
*ecmd
)
166 struct net_device
*dev
= mii
->dev
;
167 u32 speed
= ethtool_cmd_speed(ecmd
);
169 if (speed
!= SPEED_10
&&
170 speed
!= SPEED_100
&&
173 if (ecmd
->duplex
!= DUPLEX_HALF
&& ecmd
->duplex
!= DUPLEX_FULL
)
175 if (ecmd
->port
!= PORT_MII
)
177 if (ecmd
->transceiver
!= XCVR_INTERNAL
)
179 if (ecmd
->phy_address
!= mii
->phy_id
)
181 if (ecmd
->autoneg
!= AUTONEG_DISABLE
&& ecmd
->autoneg
!= AUTONEG_ENABLE
)
183 if ((speed
== SPEED_1000
) && (!mii
->supports_gmii
))
186 /* ignore supported, maxtxpkt, maxrxpkt */
188 if (ecmd
->autoneg
== AUTONEG_ENABLE
) {
189 u32 bmcr
, advert
, tmp
;
190 u32 advert2
= 0, tmp2
= 0;
192 if ((ecmd
->advertising
& (ADVERTISED_10baseT_Half
|
193 ADVERTISED_10baseT_Full
|
194 ADVERTISED_100baseT_Half
|
195 ADVERTISED_100baseT_Full
|
196 ADVERTISED_1000baseT_Half
|
197 ADVERTISED_1000baseT_Full
)) == 0)
200 /* advertise only what has been requested */
201 advert
= mii
->mdio_read(dev
, mii
->phy_id
, MII_ADVERTISE
);
202 tmp
= advert
& ~(ADVERTISE_ALL
| ADVERTISE_100BASE4
);
203 if (mii
->supports_gmii
) {
204 advert2
= mii
->mdio_read(dev
, mii
->phy_id
, MII_CTRL1000
);
205 tmp2
= advert2
& ~(ADVERTISE_1000HALF
| ADVERTISE_1000FULL
);
207 if (ecmd
->advertising
& ADVERTISED_10baseT_Half
)
208 tmp
|= ADVERTISE_10HALF
;
209 if (ecmd
->advertising
& ADVERTISED_10baseT_Full
)
210 tmp
|= ADVERTISE_10FULL
;
211 if (ecmd
->advertising
& ADVERTISED_100baseT_Half
)
212 tmp
|= ADVERTISE_100HALF
;
213 if (ecmd
->advertising
& ADVERTISED_100baseT_Full
)
214 tmp
|= ADVERTISE_100FULL
;
215 if (mii
->supports_gmii
) {
216 if (ecmd
->advertising
& ADVERTISED_1000baseT_Half
)
217 tmp2
|= ADVERTISE_1000HALF
;
218 if (ecmd
->advertising
& ADVERTISED_1000baseT_Full
)
219 tmp2
|= ADVERTISE_1000FULL
;
222 mii
->mdio_write(dev
, mii
->phy_id
, MII_ADVERTISE
, tmp
);
223 mii
->advertising
= tmp
;
225 if ((mii
->supports_gmii
) && (advert2
!= tmp2
))
226 mii
->mdio_write(dev
, mii
->phy_id
, MII_CTRL1000
, tmp2
);
228 /* turn on autonegotiation, and force a renegotiate */
229 bmcr
= mii
->mdio_read(dev
, mii
->phy_id
, MII_BMCR
);
230 bmcr
|= (BMCR_ANENABLE
| BMCR_ANRESTART
);
231 mii
->mdio_write(dev
, mii
->phy_id
, MII_BMCR
, bmcr
);
233 mii
->force_media
= 0;
237 /* turn off auto negotiation, set speed and duplexity */
238 bmcr
= mii
->mdio_read(dev
, mii
->phy_id
, MII_BMCR
);
239 tmp
= bmcr
& ~(BMCR_ANENABLE
| BMCR_SPEED100
|
240 BMCR_SPEED1000
| BMCR_FULLDPLX
);
241 if (speed
== SPEED_1000
)
242 tmp
|= BMCR_SPEED1000
;
243 else if (speed
== SPEED_100
)
244 tmp
|= BMCR_SPEED100
;
245 if (ecmd
->duplex
== DUPLEX_FULL
) {
246 tmp
|= BMCR_FULLDPLX
;
247 mii
->full_duplex
= 1;
249 mii
->full_duplex
= 0;
251 mii
->mdio_write(dev
, mii
->phy_id
, MII_BMCR
, tmp
);
253 mii
->force_media
= 1;
259 * mii_check_gmii_support - check if the MII supports Gb interfaces
260 * @mii: the MII interface
262 int mii_check_gmii_support(struct mii_if_info
*mii
)
266 reg
= mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_BMSR
);
267 if (reg
& BMSR_ESTATEN
) {
268 reg
= mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_ESTATUS
);
269 if (reg
& (ESTATUS_1000_TFULL
| ESTATUS_1000_THALF
))
277 * mii_link_ok - is link status up/ok
278 * @mii: the MII interface
280 * Returns 1 if the MII reports link status up/ok, 0 otherwise.
282 int mii_link_ok (struct mii_if_info
*mii
)
284 /* first, a dummy read, needed to latch some MII phys */
285 mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_BMSR
);
286 if (mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_BMSR
) & BMSR_LSTATUS
)
292 * mii_nway_restart - restart NWay (autonegotiation) for this interface
293 * @mii: the MII interface
295 * Returns 0 on success, negative on error.
297 int mii_nway_restart (struct mii_if_info
*mii
)
302 /* if autoneg is off, it's an error */
303 bmcr
= mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_BMCR
);
305 if (bmcr
& BMCR_ANENABLE
) {
306 bmcr
|= BMCR_ANRESTART
;
307 mii
->mdio_write(mii
->dev
, mii
->phy_id
, MII_BMCR
, bmcr
);
315 * mii_check_link - check MII link status
316 * @mii: MII interface
318 * If the link status changed (previous != current), call
319 * netif_carrier_on() if current link status is Up or call
320 * netif_carrier_off() if current link status is Down.
322 void mii_check_link (struct mii_if_info
*mii
)
324 int cur_link
= mii_link_ok(mii
);
325 int prev_link
= netif_carrier_ok(mii
->dev
);
327 if (cur_link
&& !prev_link
)
328 netif_carrier_on(mii
->dev
);
329 else if (prev_link
&& !cur_link
)
330 netif_carrier_off(mii
->dev
);
334 * mii_check_media - check the MII interface for a duplex change
335 * @mii: the MII interface
336 * @ok_to_print: OK to print link up/down messages
337 * @init_media: OK to save duplex mode in @mii
339 * Returns 1 if the duplex mode changed, 0 if not.
340 * If the media type is forced, always returns 0.
342 unsigned int mii_check_media (struct mii_if_info
*mii
,
343 unsigned int ok_to_print
,
344 unsigned int init_media
)
346 unsigned int old_carrier
, new_carrier
;
347 int advertise
, lpa
, media
, duplex
;
350 /* if forced media, go no further */
351 if (mii
->force_media
)
352 return 0; /* duplex did not change */
354 /* check current and old link status */
355 old_carrier
= netif_carrier_ok(mii
->dev
) ? 1 : 0;
356 new_carrier
= (unsigned int) mii_link_ok(mii
);
358 /* if carrier state did not change, this is a "bounce",
359 * just exit as everything is already set correctly
361 if ((!init_media
) && (old_carrier
== new_carrier
))
362 return 0; /* duplex did not change */
364 /* no carrier, nothing much to do */
366 netif_carrier_off(mii
->dev
);
368 netdev_info(mii
->dev
, "link down\n");
369 return 0; /* duplex did not change */
373 * we have carrier, see who's on the other end
375 netif_carrier_on(mii
->dev
);
377 /* get MII advertise and LPA values */
378 if ((!init_media
) && (mii
->advertising
))
379 advertise
= mii
->advertising
;
381 advertise
= mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_ADVERTISE
);
382 mii
->advertising
= advertise
;
384 lpa
= mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_LPA
);
385 if (mii
->supports_gmii
)
386 lpa2
= mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_STAT1000
);
388 /* figure out media and duplex from advertise and LPA values */
389 media
= mii_nway_result(lpa
& advertise
);
390 duplex
= (media
& ADVERTISE_FULL
) ? 1 : 0;
391 if (lpa2
& LPA_1000FULL
)
395 netdev_info(mii
->dev
, "link up, %uMbps, %s-duplex, lpa 0x%04X\n",
396 lpa2
& (LPA_1000FULL
| LPA_1000HALF
) ? 1000 :
397 media
& (ADVERTISE_100FULL
| ADVERTISE_100HALF
) ?
399 duplex
? "full" : "half",
402 if ((init_media
) || (mii
->full_duplex
!= duplex
)) {
403 mii
->full_duplex
= duplex
;
404 return 1; /* duplex changed */
407 return 0; /* duplex did not change */
411 * generic_mii_ioctl - main MII ioctl interface
412 * @mii_if: the MII interface
413 * @mii_data: MII ioctl data structure
414 * @cmd: MII ioctl command
415 * @duplex_chg_out: pointer to @duplex_changed status if there was no
418 * Returns 0 on success, negative on error.
420 int generic_mii_ioctl(struct mii_if_info
*mii_if
,
421 struct mii_ioctl_data
*mii_data
, int cmd
,
422 unsigned int *duplex_chg_out
)
425 unsigned int duplex_changed
= 0;
430 mii_data
->phy_id
&= mii_if
->phy_id_mask
;
431 mii_data
->reg_num
&= mii_if
->reg_num_mask
;
435 mii_data
->phy_id
= mii_if
->phy_id
;
440 mii_if
->mdio_read(mii_if
->dev
, mii_data
->phy_id
,
445 u16 val
= mii_data
->val_in
;
447 if (mii_data
->phy_id
== mii_if
->phy_id
) {
448 switch(mii_data
->reg_num
) {
450 unsigned int new_duplex
= 0;
451 if (val
& (BMCR_RESET
|BMCR_ANENABLE
))
452 mii_if
->force_media
= 0;
454 mii_if
->force_media
= 1;
455 if (mii_if
->force_media
&&
456 (val
& BMCR_FULLDPLX
))
458 if (mii_if
->full_duplex
!= new_duplex
) {
460 mii_if
->full_duplex
= new_duplex
;
465 mii_if
->advertising
= val
;
473 mii_if
->mdio_write(mii_if
->dev
, mii_data
->phy_id
,
474 mii_data
->reg_num
, val
);
483 if ((rc
== 0) && (duplex_chg_out
) && (duplex_changed
))
489 MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>");
490 MODULE_DESCRIPTION ("MII hardware support library");
491 MODULE_LICENSE("GPL");
493 EXPORT_SYMBOL(mii_link_ok
);
494 EXPORT_SYMBOL(mii_nway_restart
);
495 EXPORT_SYMBOL(mii_ethtool_gset
);
496 EXPORT_SYMBOL(mii_ethtool_sset
);
497 EXPORT_SYMBOL(mii_check_link
);
498 EXPORT_SYMBOL(mii_check_media
);
499 EXPORT_SYMBOL(mii_check_gmii_support
);
500 EXPORT_SYMBOL(generic_mii_ioctl
);