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 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 mii->full_duplex = cmd->base.duplex;
218 ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
220 ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
222 ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.lp_advertising,
225 /* ignore maxtxpkt, maxrxpkt for now */
229 * mii_ethtool_sset - set settings that are specified in @ecmd
230 * @mii: MII interface
231 * @ecmd: requested ethtool_cmd
233 * Returns 0 for success, negative on error.
235 int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
237 struct net_device *dev = mii->dev;
238 u32 speed = ethtool_cmd_speed(ecmd);
240 if (speed != SPEED_10 &&
241 speed != SPEED_100 &&
244 if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
246 if (ecmd->port != PORT_MII)
248 if (ecmd->transceiver != XCVR_INTERNAL)
250 if (ecmd->phy_address != mii->phy_id)
252 if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
254 if ((speed == SPEED_1000) && (!mii->supports_gmii))
257 /* ignore supported, maxtxpkt, maxrxpkt */
259 if (ecmd->autoneg == AUTONEG_ENABLE) {
260 u32 bmcr, advert, tmp;
261 u32 advert2 = 0, tmp2 = 0;
263 if ((ecmd->advertising & (ADVERTISED_10baseT_Half |
264 ADVERTISED_10baseT_Full |
265 ADVERTISED_100baseT_Half |
266 ADVERTISED_100baseT_Full |
267 ADVERTISED_1000baseT_Half |
268 ADVERTISED_1000baseT_Full)) == 0)
271 /* advertise only what has been requested */
272 advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
273 tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
274 if (mii->supports_gmii) {
275 advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
276 tmp2 = advert2 & ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
278 tmp |= ethtool_adv_to_mii_adv_t(ecmd->advertising);
280 if (mii->supports_gmii)
282 ethtool_adv_to_mii_ctrl1000_t(ecmd->advertising);
284 mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
285 mii->advertising = tmp;
287 if ((mii->supports_gmii) && (advert2 != tmp2))
288 mii->mdio_write(dev, mii->phy_id, MII_CTRL1000, tmp2);
290 /* turn on autonegotiation, and force a renegotiate */
291 bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
292 bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
293 mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
295 mii->force_media = 0;
299 /* turn off auto negotiation, set speed and duplexity */
300 bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
301 tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
302 BMCR_SPEED1000 | BMCR_FULLDPLX);
303 if (speed == SPEED_1000)
304 tmp |= BMCR_SPEED1000;
305 else if (speed == SPEED_100)
306 tmp |= BMCR_SPEED100;
307 if (ecmd->duplex == DUPLEX_FULL) {
308 tmp |= BMCR_FULLDPLX;
309 mii->full_duplex = 1;
311 mii->full_duplex = 0;
313 mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp);
315 mii->force_media = 1;
321 * mii_ethtool_set_link_ksettings - set settings that are specified in @cmd
322 * @mii: MII interfaces
323 * @cmd: requested ethtool_link_ksettings
325 * Returns 0 for success, negative on error.
327 int mii_ethtool_set_link_ksettings(struct mii_if_info *mii,
328 const struct ethtool_link_ksettings *cmd)
330 struct net_device *dev = mii->dev;
331 u32 speed = cmd->base.speed;
333 if (speed != SPEED_10 &&
334 speed != SPEED_100 &&
337 if (cmd->base.duplex != DUPLEX_HALF && cmd->base.duplex != DUPLEX_FULL)
339 if (cmd->base.port != PORT_MII)
341 if (cmd->base.phy_address != mii->phy_id)
343 if (cmd->base.autoneg != AUTONEG_DISABLE &&
344 cmd->base.autoneg != AUTONEG_ENABLE)
346 if ((speed == SPEED_1000) && (!mii->supports_gmii))
349 /* ignore supported, maxtxpkt, maxrxpkt */
351 if (cmd->base.autoneg == AUTONEG_ENABLE) {
352 u32 bmcr, advert, tmp;
353 u32 advert2 = 0, tmp2 = 0;
356 ethtool_convert_link_mode_to_legacy_u32(
357 &advertising, cmd->link_modes.advertising);
359 if ((advertising & (ADVERTISED_10baseT_Half |
360 ADVERTISED_10baseT_Full |
361 ADVERTISED_100baseT_Half |
362 ADVERTISED_100baseT_Full |
363 ADVERTISED_1000baseT_Half |
364 ADVERTISED_1000baseT_Full)) == 0)
367 /* advertise only what has been requested */
368 advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
369 tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
370 if (mii->supports_gmii) {
371 advert2 = mii->mdio_read(dev, mii->phy_id,
374 ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
376 tmp |= ethtool_adv_to_mii_adv_t(advertising);
378 if (mii->supports_gmii)
379 tmp2 |= ethtool_adv_to_mii_ctrl1000_t(advertising);
381 mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
382 mii->advertising = tmp;
384 if ((mii->supports_gmii) && (advert2 != tmp2))
385 mii->mdio_write(dev, mii->phy_id, MII_CTRL1000, tmp2);
387 /* turn on autonegotiation, and force a renegotiate */
388 bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
389 bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
390 mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
392 mii->force_media = 0;
396 /* turn off auto negotiation, set speed and duplexity */
397 bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
398 tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
399 BMCR_SPEED1000 | BMCR_FULLDPLX);
400 if (speed == SPEED_1000)
401 tmp |= BMCR_SPEED1000;
402 else if (speed == SPEED_100)
403 tmp |= BMCR_SPEED100;
404 if (cmd->base.duplex == DUPLEX_FULL) {
405 tmp |= BMCR_FULLDPLX;
406 mii->full_duplex = 1;
408 mii->full_duplex = 0;
411 mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp);
413 mii->force_media = 1;
419 * mii_check_gmii_support - check if the MII supports Gb interfaces
420 * @mii: the MII interface
422 int mii_check_gmii_support(struct mii_if_info *mii)
426 reg = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
427 if (reg & BMSR_ESTATEN) {
428 reg = mii->mdio_read(mii->dev, mii->phy_id, MII_ESTATUS);
429 if (reg & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF))
437 * mii_link_ok - is link status up/ok
438 * @mii: the MII interface
440 * Returns 1 if the MII reports link status up/ok, 0 otherwise.
442 int mii_link_ok (struct mii_if_info *mii)
444 /* first, a dummy read, needed to latch some MII phys */
445 mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
446 if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS)
452 * mii_nway_restart - restart NWay (autonegotiation) for this interface
453 * @mii: the MII interface
455 * Returns 0 on success, negative on error.
457 int mii_nway_restart (struct mii_if_info *mii)
462 /* if autoneg is off, it's an error */
463 bmcr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR);
465 if (bmcr & BMCR_ANENABLE) {
466 bmcr |= BMCR_ANRESTART;
467 mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, bmcr);
475 * mii_check_link - check MII link status
476 * @mii: MII interface
478 * If the link status changed (previous != current), call
479 * netif_carrier_on() if current link status is Up or call
480 * netif_carrier_off() if current link status is Down.
482 void mii_check_link (struct mii_if_info *mii)
484 int cur_link = mii_link_ok(mii);
485 int prev_link = netif_carrier_ok(mii->dev);
487 if (cur_link && !prev_link)
488 netif_carrier_on(mii->dev);
489 else if (prev_link && !cur_link)
490 netif_carrier_off(mii->dev);
494 * mii_check_media - check the MII interface for a carrier/speed/duplex change
495 * @mii: the MII interface
496 * @ok_to_print: OK to print link up/down messages
497 * @init_media: OK to save duplex mode in @mii
499 * Returns 1 if the duplex mode changed, 0 if not.
500 * If the media type is forced, always returns 0.
502 unsigned int mii_check_media (struct mii_if_info *mii,
503 unsigned int ok_to_print,
504 unsigned int init_media)
506 unsigned int old_carrier, new_carrier;
507 int advertise, lpa, media, duplex;
510 /* check current and old link status */
511 old_carrier = netif_carrier_ok(mii->dev) ? 1 : 0;
512 new_carrier = (unsigned int) mii_link_ok(mii);
514 /* if carrier state did not change, this is a "bounce",
515 * just exit as everything is already set correctly
517 if ((!init_media) && (old_carrier == new_carrier))
518 return 0; /* duplex did not change */
520 /* no carrier, nothing much to do */
522 netif_carrier_off(mii->dev);
524 netdev_info(mii->dev, "link down\n");
525 return 0; /* duplex did not change */
529 * we have carrier, see who's on the other end
531 netif_carrier_on(mii->dev);
533 if (mii->force_media) {
535 netdev_info(mii->dev, "link up\n");
536 return 0; /* duplex did not change */
539 /* get MII advertise and LPA values */
540 if ((!init_media) && (mii->advertising))
541 advertise = mii->advertising;
543 advertise = mii->mdio_read(mii->dev, mii->phy_id, MII_ADVERTISE);
544 mii->advertising = advertise;
546 lpa = mii->mdio_read(mii->dev, mii->phy_id, MII_LPA);
547 if (mii->supports_gmii)
548 lpa2 = mii->mdio_read(mii->dev, mii->phy_id, MII_STAT1000);
550 /* figure out media and duplex from advertise and LPA values */
551 media = mii_nway_result(lpa & advertise);
552 duplex = (media & ADVERTISE_FULL) ? 1 : 0;
553 if (lpa2 & LPA_1000FULL)
557 netdev_info(mii->dev, "link up, %uMbps, %s-duplex, lpa 0x%04X\n",
558 lpa2 & (LPA_1000FULL | LPA_1000HALF) ? 1000 :
559 media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ?
561 duplex ? "full" : "half",
564 if ((init_media) || (mii->full_duplex != duplex)) {
565 mii->full_duplex = duplex;
566 return 1; /* duplex changed */
569 return 0; /* duplex did not change */
573 * generic_mii_ioctl - main MII ioctl interface
574 * @mii_if: the MII interface
575 * @mii_data: MII ioctl data structure
576 * @cmd: MII ioctl command
577 * @duplex_chg_out: pointer to @duplex_changed status if there was no
580 * Returns 0 on success, negative on error.
582 int generic_mii_ioctl(struct mii_if_info *mii_if,
583 struct mii_ioctl_data *mii_data, int cmd,
584 unsigned int *duplex_chg_out)
587 unsigned int duplex_changed = 0;
592 mii_data->phy_id &= mii_if->phy_id_mask;
593 mii_data->reg_num &= mii_if->reg_num_mask;
597 mii_data->phy_id = mii_if->phy_id;
602 mii_if->mdio_read(mii_if->dev, mii_data->phy_id,
607 u16 val = mii_data->val_in;
609 if (mii_data->phy_id == mii_if->phy_id) {
610 switch(mii_data->reg_num) {
612 unsigned int new_duplex = 0;
613 if (val & (BMCR_RESET|BMCR_ANENABLE))
614 mii_if->force_media = 0;
616 mii_if->force_media = 1;
617 if (mii_if->force_media &&
618 (val & BMCR_FULLDPLX))
620 if (mii_if->full_duplex != new_duplex) {
622 mii_if->full_duplex = new_duplex;
627 mii_if->advertising = val;
635 mii_if->mdio_write(mii_if->dev, mii_data->phy_id,
636 mii_data->reg_num, val);
645 if ((rc == 0) && (duplex_chg_out) && (duplex_changed))
651 MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>");
652 MODULE_DESCRIPTION ("MII hardware support library");
653 MODULE_LICENSE("GPL");
655 EXPORT_SYMBOL(mii_link_ok);
656 EXPORT_SYMBOL(mii_nway_restart);
657 EXPORT_SYMBOL(mii_ethtool_gset);
658 EXPORT_SYMBOL(mii_ethtool_get_link_ksettings);
659 EXPORT_SYMBOL(mii_ethtool_sset);
660 EXPORT_SYMBOL(mii_ethtool_set_link_ksettings);
661 EXPORT_SYMBOL(mii_check_link);
662 EXPORT_SYMBOL(mii_check_media);
663 EXPORT_SYMBOL(mii_check_gmii_support);
664 EXPORT_SYMBOL(generic_mii_ioctl);