mii.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. /*
  2. mii.c: MII interface library
  3. Maintained by Jeff Garzik <jgarzik@pobox.com>
  4. Copyright 2001,2002 Jeff Garzik
  5. Various code came from myson803.c and other files by
  6. Donald Becker. Copyright:
  7. Written 1998-2002 by Donald Becker.
  8. This software may be used and distributed according
  9. to the terms of the GNU General Public License (GPL),
  10. incorporated herein by reference. Drivers based on
  11. or derived from this code fall under the GPL and must
  12. retain the authorship, copyright and license notice.
  13. This file is not a complete program and may only be
  14. used when the entire operating system is licensed
  15. under the GPL.
  16. The author may be reached as becker@scyld.com, or C/O
  17. Scyld Computing Corporation
  18. 410 Severn Ave., Suite 210
  19. Annapolis MD 21403
  20. */
  21. #include <linux/kernel.h>
  22. #include <linux/module.h>
  23. #include <linux/netdevice.h>
  24. #include <linux/ethtool.h>
  25. #include <linux/mii.h>
  26. static u32 mii_get_an(struct mii_if_info *mii, u16 addr)
  27. {
  28. int advert;
  29. advert = mii->mdio_read(mii->dev, mii->phy_id, addr);
  30. return mii_lpa_to_ethtool_lpa_t(advert);
  31. }
  32. /**
  33. * mii_ethtool_gset - get settings that are specified in @ecmd
  34. * @mii: MII interface
  35. * @ecmd: requested ethtool_cmd
  36. *
  37. * The @ecmd parameter is expected to have been cleared before calling
  38. * mii_ethtool_gset().
  39. *
  40. * Returns 0 for success, negative on error.
  41. */
  42. int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
  43. {
  44. struct net_device *dev = mii->dev;
  45. u16 bmcr, bmsr, ctrl1000 = 0, stat1000 = 0;
  46. u32 nego;
  47. ecmd->supported =
  48. (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
  49. SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
  50. SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
  51. if (mii->supports_gmii)
  52. ecmd->supported |= SUPPORTED_1000baseT_Half |
  53. SUPPORTED_1000baseT_Full;
  54. /* only supports twisted-pair */
  55. ecmd->port = PORT_MII;
  56. /* only supports internal transceiver */
  57. ecmd->transceiver = XCVR_INTERNAL;
  58. /* this isn't fully supported at higher layers */
  59. ecmd->phy_address = mii->phy_id;
  60. ecmd->mdio_support = ETH_MDIO_SUPPORTS_C22;
  61. ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
  62. bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
  63. bmsr = mii->mdio_read(dev, mii->phy_id, MII_BMSR);
  64. if (mii->supports_gmii) {
  65. ctrl1000 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
  66. stat1000 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000);
  67. }
  68. if (bmcr & BMCR_ANENABLE) {
  69. ecmd->advertising |= ADVERTISED_Autoneg;
  70. ecmd->autoneg = AUTONEG_ENABLE;
  71. ecmd->advertising |= mii_get_an(mii, MII_ADVERTISE);
  72. if (mii->supports_gmii)
  73. ecmd->advertising |=
  74. mii_ctrl1000_to_ethtool_adv_t(ctrl1000);
  75. if (bmsr & BMSR_ANEGCOMPLETE) {
  76. ecmd->lp_advertising = mii_get_an(mii, MII_LPA);
  77. ecmd->lp_advertising |=
  78. mii_stat1000_to_ethtool_lpa_t(stat1000);
  79. } else {
  80. ecmd->lp_advertising = 0;
  81. }
  82. nego = ecmd->advertising & ecmd->lp_advertising;
  83. if (nego & (ADVERTISED_1000baseT_Full |
  84. ADVERTISED_1000baseT_Half)) {
  85. ethtool_cmd_speed_set(ecmd, SPEED_1000);
  86. ecmd->duplex = !!(nego & ADVERTISED_1000baseT_Full);
  87. } else if (nego & (ADVERTISED_100baseT_Full |
  88. ADVERTISED_100baseT_Half)) {
  89. ethtool_cmd_speed_set(ecmd, SPEED_100);
  90. ecmd->duplex = !!(nego & ADVERTISED_100baseT_Full);
  91. } else {
  92. ethtool_cmd_speed_set(ecmd, SPEED_10);
  93. ecmd->duplex = !!(nego & ADVERTISED_10baseT_Full);
  94. }
  95. } else {
  96. ecmd->autoneg = AUTONEG_DISABLE;
  97. ethtool_cmd_speed_set(ecmd,
  98. ((bmcr & BMCR_SPEED1000 &&
  99. (bmcr & BMCR_SPEED100) == 0) ?
  100. SPEED_1000 :
  101. ((bmcr & BMCR_SPEED100) ?
  102. SPEED_100 : SPEED_10)));
  103. ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
  104. }
  105. mii->full_duplex = ecmd->duplex;
  106. /* ignore maxtxpkt, maxrxpkt for now */
  107. return 0;
  108. }
  109. /**
  110. * mii_ethtool_get_link_ksettings - get settings that are specified in @cmd
  111. * @mii: MII interface
  112. * @cmd: requested ethtool_link_ksettings
  113. *
  114. * The @cmd parameter is expected to have been cleared before calling
  115. * mii_ethtool_get_link_ksettings().
  116. */
  117. void mii_ethtool_get_link_ksettings(struct mii_if_info *mii,
  118. struct ethtool_link_ksettings *cmd)
  119. {
  120. struct net_device *dev = mii->dev;
  121. u16 bmcr, bmsr, ctrl1000 = 0, stat1000 = 0;
  122. u32 nego, supported, advertising, lp_advertising;
  123. supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
  124. SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
  125. SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
  126. if (mii->supports_gmii)
  127. supported |= SUPPORTED_1000baseT_Half |
  128. SUPPORTED_1000baseT_Full;
  129. /* only supports twisted-pair */
  130. cmd->base.port = PORT_MII;
  131. /* this isn't fully supported at higher layers */
  132. cmd->base.phy_address = mii->phy_id;
  133. cmd->base.mdio_support = ETH_MDIO_SUPPORTS_C22;
  134. advertising = ADVERTISED_TP | ADVERTISED_MII;
  135. bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
  136. bmsr = mii->mdio_read(dev, mii->phy_id, MII_BMSR);
  137. if (mii->supports_gmii) {
  138. ctrl1000 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
  139. stat1000 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000);
  140. }
  141. if (bmcr & BMCR_ANENABLE) {
  142. advertising |= ADVERTISED_Autoneg;
  143. cmd->base.autoneg = AUTONEG_ENABLE;
  144. advertising |= mii_get_an(mii, MII_ADVERTISE);
  145. if (mii->supports_gmii)
  146. advertising |= mii_ctrl1000_to_ethtool_adv_t(ctrl1000);
  147. if (bmsr & BMSR_ANEGCOMPLETE) {
  148. lp_advertising = mii_get_an(mii, MII_LPA);
  149. lp_advertising |=
  150. mii_stat1000_to_ethtool_lpa_t(stat1000);
  151. } else {
  152. lp_advertising = 0;
  153. }
  154. nego = advertising & lp_advertising;
  155. if (nego & (ADVERTISED_1000baseT_Full |
  156. ADVERTISED_1000baseT_Half)) {
  157. cmd->base.speed = SPEED_1000;
  158. cmd->base.duplex = !!(nego & ADVERTISED_1000baseT_Full);
  159. } else if (nego & (ADVERTISED_100baseT_Full |
  160. ADVERTISED_100baseT_Half)) {
  161. cmd->base.speed = SPEED_100;
  162. cmd->base.duplex = !!(nego & ADVERTISED_100baseT_Full);
  163. } else {
  164. cmd->base.speed = SPEED_10;
  165. cmd->base.duplex = !!(nego & ADVERTISED_10baseT_Full);
  166. }
  167. } else {
  168. cmd->base.autoneg = AUTONEG_DISABLE;
  169. cmd->base.speed = ((bmcr & BMCR_SPEED1000 &&
  170. (bmcr & BMCR_SPEED100) == 0) ?
  171. SPEED_1000 :
  172. ((bmcr & BMCR_SPEED100) ?
  173. SPEED_100 : SPEED_10));
  174. cmd->base.duplex = (bmcr & BMCR_FULLDPLX) ?
  175. DUPLEX_FULL : DUPLEX_HALF;
  176. lp_advertising = 0;
  177. }
  178. mii->full_duplex = cmd->base.duplex;
  179. ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
  180. supported);
  181. ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
  182. advertising);
  183. ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.lp_advertising,
  184. lp_advertising);
  185. /* ignore maxtxpkt, maxrxpkt for now */
  186. }
  187. /**
  188. * mii_ethtool_sset - set settings that are specified in @ecmd
  189. * @mii: MII interface
  190. * @ecmd: requested ethtool_cmd
  191. *
  192. * Returns 0 for success, negative on error.
  193. */
  194. int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
  195. {
  196. struct net_device *dev = mii->dev;
  197. u32 speed = ethtool_cmd_speed(ecmd);
  198. if (speed != SPEED_10 &&
  199. speed != SPEED_100 &&
  200. speed != SPEED_1000)
  201. return -EINVAL;
  202. if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
  203. return -EINVAL;
  204. if (ecmd->port != PORT_MII)
  205. return -EINVAL;
  206. if (ecmd->transceiver != XCVR_INTERNAL)
  207. return -EINVAL;
  208. if (ecmd->phy_address != mii->phy_id)
  209. return -EINVAL;
  210. if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
  211. return -EINVAL;
  212. if ((speed == SPEED_1000) && (!mii->supports_gmii))
  213. return -EINVAL;
  214. /* ignore supported, maxtxpkt, maxrxpkt */
  215. if (ecmd->autoneg == AUTONEG_ENABLE) {
  216. u32 bmcr, advert, tmp;
  217. u32 advert2 = 0, tmp2 = 0;
  218. if ((ecmd->advertising & (ADVERTISED_10baseT_Half |
  219. ADVERTISED_10baseT_Full |
  220. ADVERTISED_100baseT_Half |
  221. ADVERTISED_100baseT_Full |
  222. ADVERTISED_1000baseT_Half |
  223. ADVERTISED_1000baseT_Full)) == 0)
  224. return -EINVAL;
  225. /* advertise only what has been requested */
  226. advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
  227. tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
  228. if (mii->supports_gmii) {
  229. advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
  230. tmp2 = advert2 & ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
  231. }
  232. tmp |= ethtool_adv_to_mii_adv_t(ecmd->advertising);
  233. if (mii->supports_gmii)
  234. tmp2 |=
  235. ethtool_adv_to_mii_ctrl1000_t(ecmd->advertising);
  236. if (advert != tmp) {
  237. mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
  238. mii->advertising = tmp;
  239. }
  240. if ((mii->supports_gmii) && (advert2 != tmp2))
  241. mii->mdio_write(dev, mii->phy_id, MII_CTRL1000, tmp2);
  242. /* turn on autonegotiation, and force a renegotiate */
  243. bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
  244. bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
  245. mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
  246. mii->force_media = 0;
  247. } else {
  248. u32 bmcr, tmp;
  249. /* turn off auto negotiation, set speed and duplexity */
  250. bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
  251. tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
  252. BMCR_SPEED1000 | BMCR_FULLDPLX);
  253. if (speed == SPEED_1000)
  254. tmp |= BMCR_SPEED1000;
  255. else if (speed == SPEED_100)
  256. tmp |= BMCR_SPEED100;
  257. if (ecmd->duplex == DUPLEX_FULL) {
  258. tmp |= BMCR_FULLDPLX;
  259. mii->full_duplex = 1;
  260. } else
  261. mii->full_duplex = 0;
  262. if (bmcr != tmp)
  263. mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp);
  264. mii->force_media = 1;
  265. }
  266. return 0;
  267. }
  268. /**
  269. * mii_ethtool_set_link_ksettings - set settings that are specified in @cmd
  270. * @mii: MII interfaces
  271. * @cmd: requested ethtool_link_ksettings
  272. *
  273. * Returns 0 for success, negative on error.
  274. */
  275. int mii_ethtool_set_link_ksettings(struct mii_if_info *mii,
  276. const struct ethtool_link_ksettings *cmd)
  277. {
  278. struct net_device *dev = mii->dev;
  279. u32 speed = cmd->base.speed;
  280. if (speed != SPEED_10 &&
  281. speed != SPEED_100 &&
  282. speed != SPEED_1000)
  283. return -EINVAL;
  284. if (cmd->base.duplex != DUPLEX_HALF && cmd->base.duplex != DUPLEX_FULL)
  285. return -EINVAL;
  286. if (cmd->base.port != PORT_MII)
  287. return -EINVAL;
  288. if (cmd->base.phy_address != mii->phy_id)
  289. return -EINVAL;
  290. if (cmd->base.autoneg != AUTONEG_DISABLE &&
  291. cmd->base.autoneg != AUTONEG_ENABLE)
  292. return -EINVAL;
  293. if ((speed == SPEED_1000) && (!mii->supports_gmii))
  294. return -EINVAL;
  295. /* ignore supported, maxtxpkt, maxrxpkt */
  296. if (cmd->base.autoneg == AUTONEG_ENABLE) {
  297. u32 bmcr, advert, tmp;
  298. u32 advert2 = 0, tmp2 = 0;
  299. u32 advertising;
  300. ethtool_convert_link_mode_to_legacy_u32(
  301. &advertising, cmd->link_modes.advertising);
  302. if ((advertising & (ADVERTISED_10baseT_Half |
  303. ADVERTISED_10baseT_Full |
  304. ADVERTISED_100baseT_Half |
  305. ADVERTISED_100baseT_Full |
  306. ADVERTISED_1000baseT_Half |
  307. ADVERTISED_1000baseT_Full)) == 0)
  308. return -EINVAL;
  309. /* advertise only what has been requested */
  310. advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
  311. tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
  312. if (mii->supports_gmii) {
  313. advert2 = mii->mdio_read(dev, mii->phy_id,
  314. MII_CTRL1000);
  315. tmp2 = advert2 &
  316. ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
  317. }
  318. tmp |= ethtool_adv_to_mii_adv_t(advertising);
  319. if (mii->supports_gmii)
  320. tmp2 |= ethtool_adv_to_mii_ctrl1000_t(advertising);
  321. if (advert != tmp) {
  322. mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
  323. mii->advertising = tmp;
  324. }
  325. if ((mii->supports_gmii) && (advert2 != tmp2))
  326. mii->mdio_write(dev, mii->phy_id, MII_CTRL1000, tmp2);
  327. /* turn on autonegotiation, and force a renegotiate */
  328. bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
  329. bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
  330. mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
  331. mii->force_media = 0;
  332. } else {
  333. u32 bmcr, tmp;
  334. /* turn off auto negotiation, set speed and duplexity */
  335. bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
  336. tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
  337. BMCR_SPEED1000 | BMCR_FULLDPLX);
  338. if (speed == SPEED_1000)
  339. tmp |= BMCR_SPEED1000;
  340. else if (speed == SPEED_100)
  341. tmp |= BMCR_SPEED100;
  342. if (cmd->base.duplex == DUPLEX_FULL) {
  343. tmp |= BMCR_FULLDPLX;
  344. mii->full_duplex = 1;
  345. } else {
  346. mii->full_duplex = 0;
  347. }
  348. if (bmcr != tmp)
  349. mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp);
  350. mii->force_media = 1;
  351. }
  352. return 0;
  353. }
  354. /**
  355. * mii_check_gmii_support - check if the MII supports Gb interfaces
  356. * @mii: the MII interface
  357. */
  358. int mii_check_gmii_support(struct mii_if_info *mii)
  359. {
  360. int reg;
  361. reg = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
  362. if (reg & BMSR_ESTATEN) {
  363. reg = mii->mdio_read(mii->dev, mii->phy_id, MII_ESTATUS);
  364. if (reg & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF))
  365. return 1;
  366. }
  367. return 0;
  368. }
  369. /**
  370. * mii_link_ok - is link status up/ok
  371. * @mii: the MII interface
  372. *
  373. * Returns 1 if the MII reports link status up/ok, 0 otherwise.
  374. */
  375. int mii_link_ok (struct mii_if_info *mii)
  376. {
  377. /* first, a dummy read, needed to latch some MII phys */
  378. mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
  379. if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS)
  380. return 1;
  381. return 0;
  382. }
  383. /**
  384. * mii_nway_restart - restart NWay (autonegotiation) for this interface
  385. * @mii: the MII interface
  386. *
  387. * Returns 0 on success, negative on error.
  388. */
  389. int mii_nway_restart (struct mii_if_info *mii)
  390. {
  391. int bmcr;
  392. int r = -EINVAL;
  393. /* if autoneg is off, it's an error */
  394. bmcr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR);
  395. if (bmcr & BMCR_ANENABLE) {
  396. bmcr |= BMCR_ANRESTART;
  397. mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, bmcr);
  398. r = 0;
  399. }
  400. return r;
  401. }
  402. /**
  403. * mii_check_link - check MII link status
  404. * @mii: MII interface
  405. *
  406. * If the link status changed (previous != current), call
  407. * netif_carrier_on() if current link status is Up or call
  408. * netif_carrier_off() if current link status is Down.
  409. */
  410. void mii_check_link (struct mii_if_info *mii)
  411. {
  412. int cur_link = mii_link_ok(mii);
  413. int prev_link = netif_carrier_ok(mii->dev);
  414. if (cur_link && !prev_link)
  415. netif_carrier_on(mii->dev);
  416. else if (prev_link && !cur_link)
  417. netif_carrier_off(mii->dev);
  418. }
  419. /**
  420. * mii_check_media - check the MII interface for a carrier/speed/duplex change
  421. * @mii: the MII interface
  422. * @ok_to_print: OK to print link up/down messages
  423. * @init_media: OK to save duplex mode in @mii
  424. *
  425. * Returns 1 if the duplex mode changed, 0 if not.
  426. * If the media type is forced, always returns 0.
  427. */
  428. unsigned int mii_check_media (struct mii_if_info *mii,
  429. unsigned int ok_to_print,
  430. unsigned int init_media)
  431. {
  432. unsigned int old_carrier, new_carrier;
  433. int advertise, lpa, media, duplex;
  434. int lpa2 = 0;
  435. /* check current and old link status */
  436. old_carrier = netif_carrier_ok(mii->dev) ? 1 : 0;
  437. new_carrier = (unsigned int) mii_link_ok(mii);
  438. /* if carrier state did not change, this is a "bounce",
  439. * just exit as everything is already set correctly
  440. */
  441. if ((!init_media) && (old_carrier == new_carrier))
  442. return 0; /* duplex did not change */
  443. /* no carrier, nothing much to do */
  444. if (!new_carrier) {
  445. netif_carrier_off(mii->dev);
  446. if (ok_to_print)
  447. netdev_info(mii->dev, "link down\n");
  448. return 0; /* duplex did not change */
  449. }
  450. /*
  451. * we have carrier, see who's on the other end
  452. */
  453. netif_carrier_on(mii->dev);
  454. if (mii->force_media) {
  455. if (ok_to_print)
  456. netdev_info(mii->dev, "link up\n");
  457. return 0; /* duplex did not change */
  458. }
  459. /* get MII advertise and LPA values */
  460. if ((!init_media) && (mii->advertising))
  461. advertise = mii->advertising;
  462. else {
  463. advertise = mii->mdio_read(mii->dev, mii->phy_id, MII_ADVERTISE);
  464. mii->advertising = advertise;
  465. }
  466. lpa = mii->mdio_read(mii->dev, mii->phy_id, MII_LPA);
  467. if (mii->supports_gmii)
  468. lpa2 = mii->mdio_read(mii->dev, mii->phy_id, MII_STAT1000);
  469. /* figure out media and duplex from advertise and LPA values */
  470. media = mii_nway_result(lpa & advertise);
  471. duplex = (media & ADVERTISE_FULL) ? 1 : 0;
  472. if (lpa2 & LPA_1000FULL)
  473. duplex = 1;
  474. if (ok_to_print)
  475. netdev_info(mii->dev, "link up, %uMbps, %s-duplex, lpa 0x%04X\n",
  476. lpa2 & (LPA_1000FULL | LPA_1000HALF) ? 1000 :
  477. media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ?
  478. 100 : 10,
  479. duplex ? "full" : "half",
  480. lpa);
  481. if ((init_media) || (mii->full_duplex != duplex)) {
  482. mii->full_duplex = duplex;
  483. return 1; /* duplex changed */
  484. }
  485. return 0; /* duplex did not change */
  486. }
  487. /**
  488. * generic_mii_ioctl - main MII ioctl interface
  489. * @mii_if: the MII interface
  490. * @mii_data: MII ioctl data structure
  491. * @cmd: MII ioctl command
  492. * @duplex_chg_out: pointer to @duplex_changed status if there was no
  493. * ioctl error
  494. *
  495. * Returns 0 on success, negative on error.
  496. */
  497. int generic_mii_ioctl(struct mii_if_info *mii_if,
  498. struct mii_ioctl_data *mii_data, int cmd,
  499. unsigned int *duplex_chg_out)
  500. {
  501. int rc = 0;
  502. unsigned int duplex_changed = 0;
  503. if (duplex_chg_out)
  504. *duplex_chg_out = 0;
  505. mii_data->phy_id &= mii_if->phy_id_mask;
  506. mii_data->reg_num &= mii_if->reg_num_mask;
  507. switch(cmd) {
  508. case SIOCGMIIPHY:
  509. mii_data->phy_id = mii_if->phy_id;
  510. /* fall through */
  511. case SIOCGMIIREG:
  512. mii_data->val_out =
  513. mii_if->mdio_read(mii_if->dev, mii_data->phy_id,
  514. mii_data->reg_num);
  515. break;
  516. case SIOCSMIIREG: {
  517. u16 val = mii_data->val_in;
  518. if (mii_data->phy_id == mii_if->phy_id) {
  519. switch(mii_data->reg_num) {
  520. case MII_BMCR: {
  521. unsigned int new_duplex = 0;
  522. if (val & (BMCR_RESET|BMCR_ANENABLE))
  523. mii_if->force_media = 0;
  524. else
  525. mii_if->force_media = 1;
  526. if (mii_if->force_media &&
  527. (val & BMCR_FULLDPLX))
  528. new_duplex = 1;
  529. if (mii_if->full_duplex != new_duplex) {
  530. duplex_changed = 1;
  531. mii_if->full_duplex = new_duplex;
  532. }
  533. break;
  534. }
  535. case MII_ADVERTISE:
  536. mii_if->advertising = val;
  537. break;
  538. default:
  539. /* do nothing */
  540. break;
  541. }
  542. }
  543. mii_if->mdio_write(mii_if->dev, mii_data->phy_id,
  544. mii_data->reg_num, val);
  545. break;
  546. }
  547. default:
  548. rc = -EOPNOTSUPP;
  549. break;
  550. }
  551. if ((rc == 0) && (duplex_chg_out) && (duplex_changed))
  552. *duplex_chg_out = 1;
  553. return rc;
  554. }
  555. MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>");
  556. MODULE_DESCRIPTION ("MII hardware support library");
  557. MODULE_LICENSE("GPL");
  558. EXPORT_SYMBOL(mii_link_ok);
  559. EXPORT_SYMBOL(mii_nway_restart);
  560. EXPORT_SYMBOL(mii_ethtool_gset);
  561. EXPORT_SYMBOL(mii_ethtool_get_link_ksettings);
  562. EXPORT_SYMBOL(mii_ethtool_sset);
  563. EXPORT_SYMBOL(mii_ethtool_set_link_ksettings);
  564. EXPORT_SYMBOL(mii_check_link);
  565. EXPORT_SYMBOL(mii_check_media);
  566. EXPORT_SYMBOL(mii_check_gmii_support);
  567. EXPORT_SYMBOL(generic_mii_ioctl);