3 mii.c: MII interface library
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
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 void mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
55 struct net_device *dev = mii->dev;
56 u16 bmcr, bmsr, ctrl1000 = 0, stat1000 = 0;
60 (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
61 SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
62 SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
63 if (mii->supports_gmii)
64 ecmd->supported |= SUPPORTED_1000baseT_Half |
65 SUPPORTED_1000baseT_Full;
67 /* only supports twisted-pair */
68 ecmd->port = PORT_MII;
70 /* only supports internal transceiver */
71 ecmd->transceiver = XCVR_INTERNAL;
73 /* this isn't fully supported at higher layers */
74 ecmd->phy_address = mii->phy_id;
75 ecmd->mdio_support = ETH_MDIO_SUPPORTS_C22;
77 ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
79 bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
80 bmsr = mii->mdio_read(dev, mii->phy_id, MII_BMSR);
81 if (mii->supports_gmii) {
82 ctrl1000 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
83 stat1000 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000);
86 ecmd->advertising |= mii_get_an(mii, MII_ADVERTISE);
87 if (mii->supports_gmii)
89 mii_ctrl1000_to_ethtool_adv_t(ctrl1000);
91 if (bmcr & BMCR_ANENABLE) {
92 ecmd->advertising |= ADVERTISED_Autoneg;
93 ecmd->autoneg = AUTONEG_ENABLE;
95 if (bmsr & BMSR_ANEGCOMPLETE) {
96 ecmd->lp_advertising = mii_get_an(mii, MII_LPA);
97 ecmd->lp_advertising |=
98 mii_stat1000_to_ethtool_lpa_t(stat1000);
100 ecmd->lp_advertising = 0;
103 nego = ecmd->advertising & ecmd->lp_advertising;
105 if (nego & (ADVERTISED_1000baseT_Full |
106 ADVERTISED_1000baseT_Half)) {
107 ethtool_cmd_speed_set(ecmd, SPEED_1000);
108 ecmd->duplex = !!(nego & ADVERTISED_1000baseT_Full);
109 } else if (nego & (ADVERTISED_100baseT_Full |
110 ADVERTISED_100baseT_Half)) {
111 ethtool_cmd_speed_set(ecmd, SPEED_100);
112 ecmd->duplex = !!(nego & ADVERTISED_100baseT_Full);
114 ethtool_cmd_speed_set(ecmd, SPEED_10);
115 ecmd->duplex = !!(nego & ADVERTISED_10baseT_Full);
118 ecmd->autoneg = AUTONEG_DISABLE;
120 ethtool_cmd_speed_set(ecmd,
121 ((bmcr & BMCR_SPEED1000 &&
122 (bmcr & BMCR_SPEED100) == 0) ?
124 ((bmcr & BMCR_SPEED100) ?
125 SPEED_100 : SPEED_10)));
126 ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
129 mii->full_duplex = ecmd->duplex;
131 /* ignore maxtxpkt, maxrxpkt for now */
135 * mii_ethtool_get_link_ksettings - get settings that are specified in @cmd
136 * @mii: MII interface
137 * @cmd: requested ethtool_link_ksettings
139 * The @cmd parameter is expected to have been cleared before calling
140 * mii_ethtool_get_link_ksettings().
142 void mii_ethtool_get_link_ksettings(struct mii_if_info *mii,
143 struct ethtool_link_ksettings *cmd)
145 struct net_device *dev = mii->dev;
146 u16 bmcr, bmsr, ctrl1000 = 0, stat1000 = 0;
147 u32 nego, supported, advertising, lp_advertising;
149 supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
150 SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
151 SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
152 if (mii->supports_gmii)
153 supported |= SUPPORTED_1000baseT_Half |
154 SUPPORTED_1000baseT_Full;
156 /* only supports twisted-pair */
157 cmd->base.port = PORT_MII;
159 /* this isn't fully supported at higher layers */
160 cmd->base.phy_address = mii->phy_id;
161 cmd->base.mdio_support = ETH_MDIO_SUPPORTS_C22;
163 advertising = ADVERTISED_TP | ADVERTISED_MII;
165 bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
166 bmsr = mii->mdio_read(dev, mii->phy_id, MII_BMSR);
167 if (mii->supports_gmii) {
168 ctrl1000 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
169 stat1000 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000);
172 advertising |= mii_get_an(mii, MII_ADVERTISE);
173 if (mii->supports_gmii)
174 advertising |= mii_ctrl1000_to_ethtool_adv_t(ctrl1000);
176 if (bmcr & BMCR_ANENABLE) {
177 advertising |= ADVERTISED_Autoneg;
178 cmd->base.autoneg = AUTONEG_ENABLE;
180 if (bmsr & BMSR_ANEGCOMPLETE) {
181 lp_advertising = mii_get_an(mii, MII_LPA);
183 mii_stat1000_to_ethtool_lpa_t(stat1000);
188 nego = advertising & lp_advertising;
190 if (nego & (ADVERTISED_1000baseT_Full |
191 ADVERTISED_1000baseT_Half)) {
192 cmd->base.speed = SPEED_1000;
193 cmd->base.duplex = !!(nego & ADVERTISED_1000baseT_Full);
194 } else if (nego & (ADVERTISED_100baseT_Full |
195 ADVERTISED_100baseT_Half)) {
196 cmd->base.speed = SPEED_100;
197 cmd->base.duplex = !!(nego & ADVERTISED_100baseT_Full);
199 cmd->base.speed = SPEED_10;
200 cmd->base.duplex = !!(nego & ADVERTISED_10baseT_Full);
203 cmd->base.autoneg = AUTONEG_DISABLE;
205 cmd->base.speed = ((bmcr & BMCR_SPEED1000 &&
206 (bmcr & BMCR_SPEED100) == 0) ?
208 ((bmcr & BMCR_SPEED100) ?
209 SPEED_100 : SPEED_10));
210 cmd->base.duplex = (bmcr & BMCR_FULLDPLX) ?
211 DUPLEX_FULL : DUPLEX_HALF;
216 if (!(bmsr & BMSR_LSTATUS))
217 cmd->base.speed = SPEED_UNKNOWN;
219 mii->full_duplex = cmd->base.duplex;
221 ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
223 ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
225 ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.lp_advertising,
228 /* ignore maxtxpkt, maxrxpkt for now */
232 * mii_ethtool_sset - set settings that are specified in @ecmd
233 * @mii: MII interface
234 * @ecmd: requested ethtool_cmd
236 * Returns 0 for success, negative on error.
238 int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
240 struct net_device *dev = mii->dev;
241 u32 speed = ethtool_cmd_speed(ecmd);
243 if (speed != SPEED_10 &&
244 speed != SPEED_100 &&
247 if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
249 if (ecmd->port != PORT_MII)
251 if (ecmd->transceiver != XCVR_INTERNAL)
253 if (ecmd->phy_address != mii->phy_id)
255 if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
257 if ((speed == SPEED_1000) && (!mii->supports_gmii))
260 /* ignore supported, maxtxpkt, maxrxpkt */
262 if (ecmd->autoneg == AUTONEG_ENABLE) {
263 u32 bmcr, advert, tmp;
264 u32 advert2 = 0, tmp2 = 0;
266 if ((ecmd->advertising & (ADVERTISED_10baseT_Half |
267 ADVERTISED_10baseT_Full |
268 ADVERTISED_100baseT_Half |
269 ADVERTISED_100baseT_Full |
270 ADVERTISED_1000baseT_Half |
271 ADVERTISED_1000baseT_Full)) == 0)
274 /* advertise only what has been requested */
275 advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
276 tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
277 if (mii->supports_gmii) {
278 advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
279 tmp2 = advert2 & ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
281 tmp |= ethtool_adv_to_mii_adv_t(ecmd->advertising);
283 if (mii->supports_gmii)
285 ethtool_adv_to_mii_ctrl1000_t(ecmd->advertising);
287 mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
288 mii->advertising = tmp;
290 if ((mii->supports_gmii) && (advert2 != tmp2))
291 mii->mdio_write(dev, mii->phy_id, MII_CTRL1000, tmp2);
293 /* turn on autonegotiation, and force a renegotiate */
294 bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
295 bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
296 mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
298 mii->force_media = 0;
302 /* turn off auto negotiation, set speed and duplexity */
303 bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
304 tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
305 BMCR_SPEED1000 | BMCR_FULLDPLX);
306 if (speed == SPEED_1000)
307 tmp |= BMCR_SPEED1000;
308 else if (speed == SPEED_100)
309 tmp |= BMCR_SPEED100;
310 if (ecmd->duplex == DUPLEX_FULL) {
311 tmp |= BMCR_FULLDPLX;
312 mii->full_duplex = 1;
314 mii->full_duplex = 0;
316 mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp);
318 mii->force_media = 1;
324 * mii_ethtool_set_link_ksettings - set settings that are specified in @cmd
325 * @mii: MII interfaces
326 * @cmd: requested ethtool_link_ksettings
328 * Returns 0 for success, negative on error.
330 int mii_ethtool_set_link_ksettings(struct mii_if_info *mii,
331 const struct ethtool_link_ksettings *cmd)
333 struct net_device *dev = mii->dev;
334 u32 speed = cmd->base.speed;
336 if (speed != SPEED_10 &&
337 speed != SPEED_100 &&
340 if (cmd->base.duplex != DUPLEX_HALF && cmd->base.duplex != DUPLEX_FULL)
342 if (cmd->base.port != PORT_MII)
344 if (cmd->base.phy_address != mii->phy_id)
346 if (cmd->base.autoneg != AUTONEG_DISABLE &&
347 cmd->base.autoneg != AUTONEG_ENABLE)
349 if ((speed == SPEED_1000) && (!mii->supports_gmii))
352 /* ignore supported, maxtxpkt, maxrxpkt */
354 if (cmd->base.autoneg == AUTONEG_ENABLE) {
355 u32 bmcr, advert, tmp;
356 u32 advert2 = 0, tmp2 = 0;
359 ethtool_convert_link_mode_to_legacy_u32(
360 &advertising, cmd->link_modes.advertising);
362 if ((advertising & (ADVERTISED_10baseT_Half |
363 ADVERTISED_10baseT_Full |
364 ADVERTISED_100baseT_Half |
365 ADVERTISED_100baseT_Full |
366 ADVERTISED_1000baseT_Half |
367 ADVERTISED_1000baseT_Full)) == 0)
370 /* advertise only what has been requested */
371 advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
372 tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
373 if (mii->supports_gmii) {
374 advert2 = mii->mdio_read(dev, mii->phy_id,
377 ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
379 tmp |= ethtool_adv_to_mii_adv_t(advertising);
381 if (mii->supports_gmii)
382 tmp2 |= ethtool_adv_to_mii_ctrl1000_t(advertising);
384 mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
385 mii->advertising = tmp;
387 if ((mii->supports_gmii) && (advert2 != tmp2))
388 mii->mdio_write(dev, mii->phy_id, MII_CTRL1000, tmp2);
390 /* turn on autonegotiation, and force a renegotiate */
391 bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
392 bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
393 mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
395 mii->force_media = 0;
399 /* turn off auto negotiation, set speed and duplexity */
400 bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
401 tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
402 BMCR_SPEED1000 | BMCR_FULLDPLX);
403 if (speed == SPEED_1000)
404 tmp |= BMCR_SPEED1000;
405 else if (speed == SPEED_100)
406 tmp |= BMCR_SPEED100;
407 if (cmd->base.duplex == DUPLEX_FULL) {
408 tmp |= BMCR_FULLDPLX;
409 mii->full_duplex = 1;
411 mii->full_duplex = 0;
414 mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp);
416 mii->force_media = 1;
422 * mii_check_gmii_support - check if the MII supports Gb interfaces
423 * @mii: the MII interface
425 int mii_check_gmii_support(struct mii_if_info *mii)
429 reg = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
430 if (reg & BMSR_ESTATEN) {
431 reg = mii->mdio_read(mii->dev, mii->phy_id, MII_ESTATUS);
432 if (reg & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF))
440 * mii_link_ok - is link status up/ok
441 * @mii: the MII interface
443 * Returns 1 if the MII reports link status up/ok, 0 otherwise.
445 int mii_link_ok (struct mii_if_info *mii)
447 /* first, a dummy read, needed to latch some MII phys */
448 mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
449 if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS)
455 * mii_nway_restart - restart NWay (autonegotiation) for this interface
456 * @mii: the MII interface
458 * Returns 0 on success, negative on error.
460 int mii_nway_restart (struct mii_if_info *mii)
465 /* if autoneg is off, it's an error */
466 bmcr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR);
468 if (bmcr & BMCR_ANENABLE) {
469 bmcr |= BMCR_ANRESTART;
470 mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, bmcr);
478 * mii_check_link - check MII link status
479 * @mii: MII interface
481 * If the link status changed (previous != current), call
482 * netif_carrier_on() if current link status is Up or call
483 * netif_carrier_off() if current link status is Down.
485 void mii_check_link (struct mii_if_info *mii)
487 int cur_link = mii_link_ok(mii);
488 int prev_link = netif_carrier_ok(mii->dev);
490 if (cur_link && !prev_link)
491 netif_carrier_on(mii->dev);
492 else if (prev_link && !cur_link)
493 netif_carrier_off(mii->dev);
497 * mii_check_media - check the MII interface for a carrier/speed/duplex change
498 * @mii: the MII interface
499 * @ok_to_print: OK to print link up/down messages
500 * @init_media: OK to save duplex mode in @mii
502 * Returns 1 if the duplex mode changed, 0 if not.
503 * If the media type is forced, always returns 0.
505 unsigned int mii_check_media (struct mii_if_info *mii,
506 unsigned int ok_to_print,
507 unsigned int init_media)
509 unsigned int old_carrier, new_carrier;
510 int advertise, lpa, media, duplex;
513 /* check current and old link status */
514 old_carrier = netif_carrier_ok(mii->dev) ? 1 : 0;
515 new_carrier = (unsigned int) mii_link_ok(mii);
517 /* if carrier state did not change, this is a "bounce",
518 * just exit as everything is already set correctly
520 if ((!init_media) && (old_carrier == new_carrier))
521 return 0; /* duplex did not change */
523 /* no carrier, nothing much to do */
525 netif_carrier_off(mii->dev);
527 netdev_info(mii->dev, "link down\n");
528 return 0; /* duplex did not change */
532 * we have carrier, see who's on the other end
534 netif_carrier_on(mii->dev);
536 if (mii->force_media) {
538 netdev_info(mii->dev, "link up\n");
539 return 0; /* duplex did not change */
542 /* get MII advertise and LPA values */
543 if ((!init_media) && (mii->advertising))
544 advertise = mii->advertising;
546 advertise = mii->mdio_read(mii->dev, mii->phy_id, MII_ADVERTISE);
547 mii->advertising = advertise;
549 lpa = mii->mdio_read(mii->dev, mii->phy_id, MII_LPA);
550 if (mii->supports_gmii)
551 lpa2 = mii->mdio_read(mii->dev, mii->phy_id, MII_STAT1000);
553 /* figure out media and duplex from advertise and LPA values */
554 media = mii_nway_result(lpa & advertise);
555 duplex = (media & ADVERTISE_FULL) ? 1 : 0;
556 if (lpa2 & LPA_1000FULL)
560 netdev_info(mii->dev, "link up, %uMbps, %s-duplex, lpa 0x%04X\n",
561 lpa2 & (LPA_1000FULL | LPA_1000HALF) ? 1000 :
562 media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ?
564 duplex ? "full" : "half",
567 if ((init_media) || (mii->full_duplex != duplex)) {
568 mii->full_duplex = duplex;
569 return 1; /* duplex changed */
572 return 0; /* duplex did not change */
576 * generic_mii_ioctl - main MII ioctl interface
577 * @mii_if: the MII interface
578 * @mii_data: MII ioctl data structure
579 * @cmd: MII ioctl command
580 * @duplex_chg_out: pointer to @duplex_changed status if there was no
583 * Returns 0 on success, negative on error.
585 int generic_mii_ioctl(struct mii_if_info *mii_if,
586 struct mii_ioctl_data *mii_data, int cmd,
587 unsigned int *duplex_chg_out)
590 unsigned int duplex_changed = 0;
595 mii_data->phy_id &= mii_if->phy_id_mask;
596 mii_data->reg_num &= mii_if->reg_num_mask;
600 mii_data->phy_id = mii_if->phy_id;
605 mii_if->mdio_read(mii_if->dev, mii_data->phy_id,
610 u16 val = mii_data->val_in;
612 if (mii_data->phy_id == mii_if->phy_id) {
613 switch(mii_data->reg_num) {
615 unsigned int new_duplex = 0;
616 if (val & (BMCR_RESET|BMCR_ANENABLE))
617 mii_if->force_media = 0;
619 mii_if->force_media = 1;
620 if (mii_if->force_media &&
621 (val & BMCR_FULLDPLX))
623 if (mii_if->full_duplex != new_duplex) {
625 mii_if->full_duplex = new_duplex;
630 mii_if->advertising = val;
638 mii_if->mdio_write(mii_if->dev, mii_data->phy_id,
639 mii_data->reg_num, val);
648 if ((rc == 0) && (duplex_chg_out) && (duplex_changed))
655 MODULE_DESCRIPTION ("MII hardware support library");
656 MODULE_LICENSE("GPL");
658 EXPORT_SYMBOL(mii_link_ok);
659 EXPORT_SYMBOL(mii_nway_restart);
660 EXPORT_SYMBOL(mii_ethtool_gset);
661 EXPORT_SYMBOL(mii_ethtool_get_link_ksettings);
662 EXPORT_SYMBOL(mii_ethtool_sset);
663 EXPORT_SYMBOL(mii_ethtool_set_link_ksettings);
664 EXPORT_SYMBOL(mii_check_link);
665 EXPORT_SYMBOL(mii_check_media);
666 EXPORT_SYMBOL(mii_check_gmii_support);
667 EXPORT_SYMBOL(generic_mii_ioctl);