You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

mii.c 4.0KB

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