1/* 2 3 mii.c: MII interface library 4 5 Ported to gPXE by Daniel Verkamp <daniel@drv.nu> 6 from Linux drivers/net/mii.c 7 8 Maintained by Jeff Garzik <jgarzik@pobox.com> 9 Copyright 2001,2002 Jeff Garzik 10 11 Various code came from myson803.c and other files by 12 Donald Becker. Copyright: 13 14 Written 1998-2002 by Donald Becker. 15 16 This software may be used and distributed according 17 to the terms of the GNU General Public License (GPL), 18 incorporated herein by reference. Drivers based on 19 or derived from this code fall under the GPL and must 20 retain the authorship, copyright and license notice. 21 This file is not a complete program and may only be 22 used when the entire operating system is licensed 23 under the GPL. 24 25 The author may be reached as becker@scyld.com, or C/O 26 Scyld Computing Corporation 27 410 Severn Ave., Suite 210 28 Annapolis MD 21403 29 30*/ 31 32#include <mii.h> 33 34/** 35 * mii_link_ok - is link status up/ok 36 * @mii: the MII interface 37 * 38 * Returns 1 if the MII reports link status up/ok, 0 otherwise. 39 */ 40int 41mii_link_ok ( struct mii_if_info *mii ) 42{ 43 /* first, a dummy read, needed to latch some MII phys */ 44 mii->mdio_read ( mii->dev, mii->phy_id, MII_BMSR ); 45 if ( mii->mdio_read ( mii->dev, mii->phy_id, MII_BMSR ) & BMSR_LSTATUS ) 46 return 1; 47 return 0; 48} 49 50/** 51 * mii_check_link - check MII link status 52 * @mii: MII interface 53 * 54 * If the link status changed (previous != current), call 55 * netif_carrier_on() if current link status is Up or call 56 * netif_carrier_off() if current link status is Down. 57 */ 58void 59mii_check_link ( struct mii_if_info *mii ) 60{ 61 int cur_link = mii_link_ok ( mii ); 62 int prev_link = netdev_link_ok ( mii->dev ); 63 64 if ( cur_link && !prev_link ) 65 netdev_link_up ( mii->dev ); 66 else if (prev_link && !cur_link) 67 netdev_link_down ( mii->dev ); 68} 69 70 71/** 72 * mii_check_media - check the MII interface for a duplex change 73 * @mii: the MII interface 74 * @ok_to_print: OK to print link up/down messages 75 * @init_media: OK to save duplex mode in @mii 76 * 77 * Returns 1 if the duplex mode changed, 0 if not. 78 * If the media type is forced, always returns 0. 79 */ 80unsigned int 81mii_check_media ( struct mii_if_info *mii, 82 unsigned int ok_to_print, 83 unsigned int init_media ) 84{ 85 unsigned int old_carrier, new_carrier; 86 int advertise, lpa, media, duplex; 87 int lpa2 = 0; 88 89 /* if forced media, go no further */ 90 if (mii->force_media) 91 return 0; /* duplex did not change */ 92 93 /* check current and old link status */ 94 old_carrier = netdev_link_ok ( mii->dev ) ? 1 : 0; 95 new_carrier = (unsigned int) mii_link_ok ( mii ); 96 97 /* if carrier state did not change, this is a "bounce", 98 * just exit as everything is already set correctly 99 */ 100 if ( ( ! init_media ) && ( old_carrier == new_carrier ) ) 101 return 0; /* duplex did not change */ 102 103 /* no carrier, nothing much to do */ 104 if ( ! new_carrier ) { 105 netdev_link_down ( mii->dev ); 106 if ( ok_to_print ) 107 DBG ( "%s: link down\n", mii->dev->name); 108 return 0; /* duplex did not change */ 109 } 110 111 /* 112 * we have carrier, see who's on the other end 113 */ 114 netdev_link_up ( mii->dev ); 115 116 /* get MII advertise and LPA values */ 117 if ( ( ! init_media ) && ( mii->advertising ) ) { 118 advertise = mii->advertising; 119 } else { 120 advertise = mii->mdio_read ( mii->dev, mii->phy_id, MII_ADVERTISE ); 121 mii->advertising = advertise; 122 } 123 lpa = mii->mdio_read ( mii->dev, mii->phy_id, MII_LPA ); 124 if ( mii->supports_gmii ) 125 lpa2 = mii->mdio_read ( mii->dev, mii->phy_id, MII_STAT1000 ); 126 127 /* figure out media and duplex from advertise and LPA values */ 128 media = mii_nway_result ( lpa & advertise ); 129 duplex = ( media & ADVERTISE_FULL ) ? 1 : 0; 130 if ( lpa2 & LPA_1000FULL ) 131 duplex = 1; 132 133 if ( ok_to_print ) 134 DBG ( "%s: link up, %sMbps, %s-duplex, lpa 0x%04X\n", 135 mii->dev->name, 136 lpa2 & ( LPA_1000FULL | LPA_1000HALF ) ? "1000" : 137 media & ( ADVERTISE_100FULL | ADVERTISE_100HALF ) ? "100" : "10", 138 duplex ? "full" : "half", 139 lpa); 140 141 if ( ( init_media ) || ( mii->full_duplex != duplex ) ) { 142 mii->full_duplex = duplex; 143 return 1; /* duplex changed */ 144 } 145 146 return 0; /* duplex did not change */ 147} 148