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 * Returns 0 for success, negative on error.
63 int mii_ethtool_gset(struct mii_if_info
*mii
, struct ethtool_cmd
*ecmd
)
65 struct net_device
*dev
= mii
->dev
;
66 u16 bmcr
, bmsr
, ctrl1000
= 0, stat1000
= 0;
70 (SUPPORTED_10baseT_Half
| SUPPORTED_10baseT_Full
|
71 SUPPORTED_100baseT_Half
| SUPPORTED_100baseT_Full
|
72 SUPPORTED_Autoneg
| SUPPORTED_TP
| SUPPORTED_MII
);
73 if (mii
->supports_gmii
)
74 ecmd
->supported
|= SUPPORTED_1000baseT_Half
|
75 SUPPORTED_1000baseT_Full
;
77 /* only supports twisted-pair */
78 ecmd
->port
= PORT_MII
;
80 /* only supports internal transceiver */
81 ecmd
->transceiver
= XCVR_INTERNAL
;
83 /* this isn't fully supported at higher layers */
84 ecmd
->phy_address
= mii
->phy_id
;
85 ecmd
->mdio_support
= MDIO_SUPPORTS_C22
;
87 ecmd
->advertising
= ADVERTISED_TP
| ADVERTISED_MII
;
89 bmcr
= mii
->mdio_read(dev
, mii
->phy_id
, MII_BMCR
);
90 bmsr
= mii
->mdio_read(dev
, mii
->phy_id
, MII_BMSR
);
91 if (mii
->supports_gmii
) {
92 ctrl1000
= mii
->mdio_read(dev
, mii
->phy_id
, MII_CTRL1000
);
93 stat1000
= mii
->mdio_read(dev
, mii
->phy_id
, MII_STAT1000
);
95 if (bmcr
& BMCR_ANENABLE
) {
96 ecmd
->advertising
|= ADVERTISED_Autoneg
;
97 ecmd
->autoneg
= AUTONEG_ENABLE
;
99 ecmd
->advertising
|= mii_get_an(mii
, MII_ADVERTISE
);
100 if (ctrl1000
& ADVERTISE_1000HALF
)
101 ecmd
->advertising
|= ADVERTISED_1000baseT_Half
;
102 if (ctrl1000
& ADVERTISE_1000FULL
)
103 ecmd
->advertising
|= ADVERTISED_1000baseT_Full
;
105 if (bmsr
& BMSR_ANEGCOMPLETE
) {
106 ecmd
->lp_advertising
= mii_get_an(mii
, MII_LPA
);
107 if (stat1000
& LPA_1000HALF
)
108 ecmd
->lp_advertising
|=
109 ADVERTISED_1000baseT_Half
;
110 if (stat1000
& LPA_1000FULL
)
111 ecmd
->lp_advertising
|=
112 ADVERTISED_1000baseT_Full
;
114 ecmd
->lp_advertising
= 0;
117 nego
= ecmd
->advertising
& ecmd
->lp_advertising
;
119 if (nego
& (ADVERTISED_1000baseT_Full
|
120 ADVERTISED_1000baseT_Half
)) {
121 ecmd
->speed
= SPEED_1000
;
122 ecmd
->duplex
= !!(nego
& ADVERTISED_1000baseT_Full
);
123 } else if (nego
& (ADVERTISED_100baseT_Full
|
124 ADVERTISED_100baseT_Half
)) {
125 ecmd
->speed
= SPEED_100
;
126 ecmd
->duplex
= !!(nego
& ADVERTISED_100baseT_Full
);
128 ecmd
->speed
= SPEED_10
;
129 ecmd
->duplex
= !!(nego
& ADVERTISED_10baseT_Full
);
132 ecmd
->autoneg
= AUTONEG_DISABLE
;
134 ecmd
->speed
= ((bmcr
& BMCR_SPEED1000
&&
135 (bmcr
& BMCR_SPEED100
) == 0) ? SPEED_1000
:
136 (bmcr
& BMCR_SPEED100
) ? SPEED_100
: SPEED_10
);
137 ecmd
->duplex
= (bmcr
& BMCR_FULLDPLX
) ? DUPLEX_FULL
: DUPLEX_HALF
;
140 mii
->full_duplex
= ecmd
->duplex
;
142 /* ignore maxtxpkt, maxrxpkt for now */
148 * mii_ethtool_sset - set settings that are specified in @ecmd
149 * @mii: MII interface
150 * @ecmd: requested ethtool_cmd
152 * Returns 0 for success, negative on error.
154 int mii_ethtool_sset(struct mii_if_info
*mii
, struct ethtool_cmd
*ecmd
)
156 struct net_device
*dev
= mii
->dev
;
158 if (ecmd
->speed
!= SPEED_10
&&
159 ecmd
->speed
!= SPEED_100
&&
160 ecmd
->speed
!= SPEED_1000
)
162 if (ecmd
->duplex
!= DUPLEX_HALF
&& ecmd
->duplex
!= DUPLEX_FULL
)
164 if (ecmd
->port
!= PORT_MII
)
166 if (ecmd
->transceiver
!= XCVR_INTERNAL
)
168 if (ecmd
->phy_address
!= mii
->phy_id
)
170 if (ecmd
->autoneg
!= AUTONEG_DISABLE
&& ecmd
->autoneg
!= AUTONEG_ENABLE
)
172 if ((ecmd
->speed
== SPEED_1000
) && (!mii
->supports_gmii
))
175 /* ignore supported, maxtxpkt, maxrxpkt */
177 if (ecmd
->autoneg
== AUTONEG_ENABLE
) {
178 u32 bmcr
, advert
, tmp
;
179 u32 advert2
= 0, tmp2
= 0;
181 if ((ecmd
->advertising
& (ADVERTISED_10baseT_Half
|
182 ADVERTISED_10baseT_Full
|
183 ADVERTISED_100baseT_Half
|
184 ADVERTISED_100baseT_Full
|
185 ADVERTISED_1000baseT_Half
|
186 ADVERTISED_1000baseT_Full
)) == 0)
189 /* advertise only what has been requested */
190 advert
= mii
->mdio_read(dev
, mii
->phy_id
, MII_ADVERTISE
);
191 tmp
= advert
& ~(ADVERTISE_ALL
| ADVERTISE_100BASE4
);
192 if (mii
->supports_gmii
) {
193 advert2
= mii
->mdio_read(dev
, mii
->phy_id
, MII_CTRL1000
);
194 tmp2
= advert2
& ~(ADVERTISE_1000HALF
| ADVERTISE_1000FULL
);
196 if (ecmd
->advertising
& ADVERTISED_10baseT_Half
)
197 tmp
|= ADVERTISE_10HALF
;
198 if (ecmd
->advertising
& ADVERTISED_10baseT_Full
)
199 tmp
|= ADVERTISE_10FULL
;
200 if (ecmd
->advertising
& ADVERTISED_100baseT_Half
)
201 tmp
|= ADVERTISE_100HALF
;
202 if (ecmd
->advertising
& ADVERTISED_100baseT_Full
)
203 tmp
|= ADVERTISE_100FULL
;
204 if (mii
->supports_gmii
) {
205 if (ecmd
->advertising
& ADVERTISED_1000baseT_Half
)
206 tmp2
|= ADVERTISE_1000HALF
;
207 if (ecmd
->advertising
& ADVERTISED_1000baseT_Full
)
208 tmp2
|= ADVERTISE_1000FULL
;
211 mii
->mdio_write(dev
, mii
->phy_id
, MII_ADVERTISE
, tmp
);
212 mii
->advertising
= tmp
;
214 if ((mii
->supports_gmii
) && (advert2
!= tmp2
))
215 mii
->mdio_write(dev
, mii
->phy_id
, MII_CTRL1000
, tmp2
);
217 /* turn on autonegotiation, and force a renegotiate */
218 bmcr
= mii
->mdio_read(dev
, mii
->phy_id
, MII_BMCR
);
219 bmcr
|= (BMCR_ANENABLE
| BMCR_ANRESTART
);
220 mii
->mdio_write(dev
, mii
->phy_id
, MII_BMCR
, bmcr
);
222 mii
->force_media
= 0;
226 /* turn off auto negotiation, set speed and duplexity */
227 bmcr
= mii
->mdio_read(dev
, mii
->phy_id
, MII_BMCR
);
228 tmp
= bmcr
& ~(BMCR_ANENABLE
| BMCR_SPEED100
|
229 BMCR_SPEED1000
| BMCR_FULLDPLX
);
230 if (ecmd
->speed
== SPEED_1000
)
231 tmp
|= BMCR_SPEED1000
;
232 else if (ecmd
->speed
== SPEED_100
)
233 tmp
|= BMCR_SPEED100
;
234 if (ecmd
->duplex
== DUPLEX_FULL
) {
235 tmp
|= BMCR_FULLDPLX
;
236 mii
->full_duplex
= 1;
238 mii
->full_duplex
= 0;
240 mii
->mdio_write(dev
, mii
->phy_id
, MII_BMCR
, tmp
);
242 mii
->force_media
= 1;
248 * mii_check_gmii_support - check if the MII supports Gb interfaces
249 * @mii: the MII interface
251 int mii_check_gmii_support(struct mii_if_info
*mii
)
255 reg
= mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_BMSR
);
256 if (reg
& BMSR_ESTATEN
) {
257 reg
= mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_ESTATUS
);
258 if (reg
& (ESTATUS_1000_TFULL
| ESTATUS_1000_THALF
))
266 * mii_link_ok - is link status up/ok
267 * @mii: the MII interface
269 * Returns 1 if the MII reports link status up/ok, 0 otherwise.
271 int mii_link_ok (struct mii_if_info
*mii
)
273 /* first, a dummy read, needed to latch some MII phys */
274 mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_BMSR
);
275 if (mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_BMSR
) & BMSR_LSTATUS
)
281 * mii_nway_restart - restart NWay (autonegotiation) for this interface
282 * @mii: the MII interface
284 * Returns 0 on success, negative on error.
286 int mii_nway_restart (struct mii_if_info
*mii
)
291 /* if autoneg is off, it's an error */
292 bmcr
= mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_BMCR
);
294 if (bmcr
& BMCR_ANENABLE
) {
295 bmcr
|= BMCR_ANRESTART
;
296 mii
->mdio_write(mii
->dev
, mii
->phy_id
, MII_BMCR
, bmcr
);
304 * mii_check_link - check MII link status
305 * @mii: MII interface
307 * If the link status changed (previous != current), call
308 * netif_carrier_on() if current link status is Up or call
309 * netif_carrier_off() if current link status is Down.
311 void mii_check_link (struct mii_if_info
*mii
)
313 int cur_link
= mii_link_ok(mii
);
314 int prev_link
= netif_carrier_ok(mii
->dev
);
316 if (cur_link
&& !prev_link
)
317 netif_carrier_on(mii
->dev
);
318 else if (prev_link
&& !cur_link
)
319 netif_carrier_off(mii
->dev
);
323 * mii_check_media - check the MII interface for a duplex change
324 * @mii: the MII interface
325 * @ok_to_print: OK to print link up/down messages
326 * @init_media: OK to save duplex mode in @mii
328 * Returns 1 if the duplex mode changed, 0 if not.
329 * If the media type is forced, always returns 0.
331 unsigned int mii_check_media (struct mii_if_info
*mii
,
332 unsigned int ok_to_print
,
333 unsigned int init_media
)
335 unsigned int old_carrier
, new_carrier
;
336 int advertise
, lpa
, media
, duplex
;
339 /* if forced media, go no further */
340 if (mii
->force_media
)
341 return 0; /* duplex did not change */
343 /* check current and old link status */
344 old_carrier
= netif_carrier_ok(mii
->dev
) ? 1 : 0;
345 new_carrier
= (unsigned int) mii_link_ok(mii
);
347 /* if carrier state did not change, this is a "bounce",
348 * just exit as everything is already set correctly
350 if ((!init_media
) && (old_carrier
== new_carrier
))
351 return 0; /* duplex did not change */
353 /* no carrier, nothing much to do */
355 netif_carrier_off(mii
->dev
);
357 printk(KERN_INFO
"%s: link down\n", mii
->dev
->name
);
358 return 0; /* duplex did not change */
362 * we have carrier, see who's on the other end
364 netif_carrier_on(mii
->dev
);
366 /* get MII advertise and LPA values */
367 if ((!init_media
) && (mii
->advertising
))
368 advertise
= mii
->advertising
;
370 advertise
= mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_ADVERTISE
);
371 mii
->advertising
= advertise
;
373 lpa
= mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_LPA
);
374 if (mii
->supports_gmii
)
375 lpa2
= mii
->mdio_read(mii
->dev
, mii
->phy_id
, MII_STAT1000
);
377 /* figure out media and duplex from advertise and LPA values */
378 media
= mii_nway_result(lpa
& advertise
);
379 duplex
= (media
& ADVERTISE_FULL
) ? 1 : 0;
380 if (lpa2
& LPA_1000FULL
)
384 printk(KERN_INFO
"%s: link up, %sMbps, %s-duplex, lpa 0x%04X\n",
386 lpa2
& (LPA_1000FULL
| LPA_1000HALF
) ? "1000" :
387 media
& (ADVERTISE_100FULL
| ADVERTISE_100HALF
) ? "100" : "10",
388 duplex
? "full" : "half",
391 if ((init_media
) || (mii
->full_duplex
!= duplex
)) {
392 mii
->full_duplex
= duplex
;
393 return 1; /* duplex changed */
396 return 0; /* duplex did not change */
400 * generic_mii_ioctl - main MII ioctl interface
401 * @mii_if: the MII interface
402 * @mii_data: MII ioctl data structure
403 * @cmd: MII ioctl command
404 * @duplex_chg_out: pointer to @duplex_changed status if there was no
407 * Returns 0 on success, negative on error.
409 int generic_mii_ioctl(struct mii_if_info
*mii_if
,
410 struct mii_ioctl_data
*mii_data
, int cmd
,
411 unsigned int *duplex_chg_out
)
414 unsigned int duplex_changed
= 0;
419 mii_data
->phy_id
&= mii_if
->phy_id_mask
;
420 mii_data
->reg_num
&= mii_if
->reg_num_mask
;
424 mii_data
->phy_id
= mii_if
->phy_id
;
429 mii_if
->mdio_read(mii_if
->dev
, mii_data
->phy_id
,
434 u16 val
= mii_data
->val_in
;
436 if (mii_data
->phy_id
== mii_if
->phy_id
) {
437 switch(mii_data
->reg_num
) {
439 unsigned int new_duplex
= 0;
440 if (val
& (BMCR_RESET
|BMCR_ANENABLE
))
441 mii_if
->force_media
= 0;
443 mii_if
->force_media
= 1;
444 if (mii_if
->force_media
&&
445 (val
& BMCR_FULLDPLX
))
447 if (mii_if
->full_duplex
!= new_duplex
) {
449 mii_if
->full_duplex
= new_duplex
;
454 mii_if
->advertising
= val
;
462 mii_if
->mdio_write(mii_if
->dev
, mii_data
->phy_id
,
463 mii_data
->reg_num
, val
);
472 if ((rc
== 0) && (duplex_chg_out
) && (duplex_changed
))
478 MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>");
479 MODULE_DESCRIPTION ("MII hardware support library");
480 MODULE_LICENSE("GPL");
482 EXPORT_SYMBOL(mii_link_ok
);
483 EXPORT_SYMBOL(mii_nway_restart
);
484 EXPORT_SYMBOL(mii_ethtool_gset
);
485 EXPORT_SYMBOL(mii_ethtool_sset
);
486 EXPORT_SYMBOL(mii_check_link
);
487 EXPORT_SYMBOL(mii_check_media
);
488 EXPORT_SYMBOL(mii_check_gmii_support
);
489 EXPORT_SYMBOL(generic_mii_ioctl
);