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/mdio.h>
36 static u32 mii_get_an(struct mii_if_info *mii, u16 addr)
41 advert = mii->mdio_read(mii->dev, mii->phy_id, addr);
42 if (advert & LPA_LPACK)
43 result |= ADVERTISED_Autoneg;
44 if (advert & ADVERTISE_10HALF)
45 result |= ADVERTISED_10baseT_Half;
46 if (advert & ADVERTISE_10FULL)
47 result |= ADVERTISED_10baseT_Full;
48 if (advert & ADVERTISE_100HALF)
49 result |= ADVERTISED_100baseT_Half;
50 if (advert & ADVERTISE_100FULL)
51 result |= ADVERTISED_100baseT_Full;
57 * mii_ethtool_gset - get settings that are specified in @ecmd
59 * @ecmd: requested ethtool_cmd
61 * The @ecmd parameter is expected to have been cleared before calling
64 * Returns 0 for success, negative on error.
66 int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
68 struct net_device *dev = mii->dev;
69 u16 bmcr, bmsr, ctrl1000 = 0, stat1000 = 0;
73 (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
74 SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
75 SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
76 if (mii->supports_gmii)
77 ecmd->supported |= SUPPORTED_1000baseT_Half |
78 SUPPORTED_1000baseT_Full;
80 /* only supports twisted-pair */
81 ecmd->port = PORT_MII;
83 /* only supports internal transceiver */
84 ecmd->transceiver = XCVR_INTERNAL;
86 /* this isn't fully supported at higher layers */
87 ecmd->phy_address = mii->phy_id;
88 ecmd->mdio_support = MDIO_SUPPORTS_C22;
90 ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
92 bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
93 bmsr = mii->mdio_read(dev, mii->phy_id, MII_BMSR);
94 if (mii->supports_gmii) {
95 ctrl1000 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
96 stat1000 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000);
98 if (bmcr & BMCR_ANENABLE) {
99 ecmd->advertising |= ADVERTISED_Autoneg;
100 ecmd->autoneg = AUTONEG_ENABLE;
102 ecmd->advertising |= mii_get_an(mii, MII_ADVERTISE);
103 if (ctrl1000 & ADVERTISE_1000HALF)
104 ecmd->advertising |= ADVERTISED_1000baseT_Half;
105 if (ctrl1000 & ADVERTISE_1000FULL)
106 ecmd->advertising |= ADVERTISED_1000baseT_Full;
108 if (bmsr & BMSR_ANEGCOMPLETE) {
109 ecmd->lp_advertising = mii_get_an(mii, MII_LPA);
110 if (stat1000 & LPA_1000HALF)
111 ecmd->lp_advertising |=
112 ADVERTISED_1000baseT_Half;
113 if (stat1000 & LPA_1000FULL)
114 ecmd->lp_advertising |=
115 ADVERTISED_1000baseT_Full;
117 ecmd->lp_advertising = 0;
120 nego = ecmd->advertising & ecmd->lp_advertising;
122 if (nego & (ADVERTISED_1000baseT_Full |
123 ADVERTISED_1000baseT_Half)) {
124 ecmd->speed = SPEED_1000;
125 ecmd->duplex = !!(nego & ADVERTISED_1000baseT_Full);
126 } else if (nego & (ADVERTISED_100baseT_Full |
127 ADVERTISED_100baseT_Half)) {
128 ecmd->speed = SPEED_100;
129 ecmd->duplex = !!(nego & ADVERTISED_100baseT_Full);
131 ecmd->speed = SPEED_10;
132 ecmd->duplex = !!(nego & ADVERTISED_10baseT_Full);
135 ecmd->autoneg = AUTONEG_DISABLE;
137 ecmd->speed = ((bmcr & BMCR_SPEED1000 &&
138 (bmcr & BMCR_SPEED100) == 0) ? SPEED_1000 :
139 (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10);
140 ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
143 mii->full_duplex = ecmd->duplex;
145 /* ignore maxtxpkt, maxrxpkt for now */
151 * mii_ethtool_sset - set settings that are specified in @ecmd
152 * @mii: MII interface
153 * @ecmd: requested ethtool_cmd
155 * Returns 0 for success, negative on error.
157 int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
159 struct net_device *dev = mii->dev;
161 if (ecmd->speed != SPEED_10 &&
162 ecmd->speed != SPEED_100 &&
163 ecmd->speed != SPEED_1000)
165 if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
167 if (ecmd->port != PORT_MII)
169 if (ecmd->transceiver != XCVR_INTERNAL)
171 if (ecmd->phy_address != mii->phy_id)
173 if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
175 if ((ecmd->speed == SPEED_1000) && (!mii->supports_gmii))
178 /* ignore supported, maxtxpkt, maxrxpkt */
180 if (ecmd->autoneg == AUTONEG_ENABLE) {
181 u32 bmcr, advert, tmp;
182 u32 advert2 = 0, tmp2 = 0;
184 if ((ecmd->advertising & (ADVERTISED_10baseT_Half |
185 ADVERTISED_10baseT_Full |
186 ADVERTISED_100baseT_Half |
187 ADVERTISED_100baseT_Full |
188 ADVERTISED_1000baseT_Half |
189 ADVERTISED_1000baseT_Full)) == 0)
192 /* advertise only what has been requested */
193 advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
194 tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
195 if (mii->supports_gmii) {
196 advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
197 tmp2 = advert2 & ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
199 if (ecmd->advertising & ADVERTISED_10baseT_Half)
200 tmp |= ADVERTISE_10HALF;
201 if (ecmd->advertising & ADVERTISED_10baseT_Full)
202 tmp |= ADVERTISE_10FULL;
203 if (ecmd->advertising & ADVERTISED_100baseT_Half)
204 tmp |= ADVERTISE_100HALF;
205 if (ecmd->advertising & ADVERTISED_100baseT_Full)
206 tmp |= ADVERTISE_100FULL;
207 if (mii->supports_gmii) {
208 if (ecmd->advertising & ADVERTISED_1000baseT_Half)
209 tmp2 |= ADVERTISE_1000HALF;
210 if (ecmd->advertising & ADVERTISED_1000baseT_Full)
211 tmp2 |= ADVERTISE_1000FULL;
214 mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
215 mii->advertising = tmp;
217 if ((mii->supports_gmii) && (advert2 != tmp2))
218 mii->mdio_write(dev, mii->phy_id, MII_CTRL1000, tmp2);
220 /* turn on autonegotiation, and force a renegotiate */
221 bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
222 bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
223 mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
225 mii->force_media = 0;
229 /* turn off auto negotiation, set speed and duplexity */
230 bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
231 tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
232 BMCR_SPEED1000 | BMCR_FULLDPLX);
233 if (ecmd->speed == SPEED_1000)
234 tmp |= BMCR_SPEED1000;
235 else if (ecmd->speed == SPEED_100)
236 tmp |= BMCR_SPEED100;
237 if (ecmd->duplex == DUPLEX_FULL) {
238 tmp |= BMCR_FULLDPLX;
239 mii->full_duplex = 1;
241 mii->full_duplex = 0;
243 mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp);
245 mii->force_media = 1;
251 * mii_check_gmii_support - check if the MII supports Gb interfaces
252 * @mii: the MII interface
254 int mii_check_gmii_support(struct mii_if_info *mii)
258 reg = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
259 if (reg & BMSR_ESTATEN) {
260 reg = mii->mdio_read(mii->dev, mii->phy_id, MII_ESTATUS);
261 if (reg & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF))
269 * mii_link_ok - is link status up/ok
270 * @mii: the MII interface
272 * Returns 1 if the MII reports link status up/ok, 0 otherwise.
274 int mii_link_ok (struct mii_if_info *mii)
276 /* first, a dummy read, needed to latch some MII phys */
277 mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
278 if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS)
284 * mii_nway_restart - restart NWay (autonegotiation) for this interface
285 * @mii: the MII interface
287 * Returns 0 on success, negative on error.
289 int mii_nway_restart (struct mii_if_info *mii)
294 /* if autoneg is off, it's an error */
295 bmcr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR);
297 if (bmcr & BMCR_ANENABLE) {
298 bmcr |= BMCR_ANRESTART;
299 mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, bmcr);
307 * mii_check_link - check MII link status
308 * @mii: MII interface
310 * If the link status changed (previous != current), call
311 * netif_carrier_on() if current link status is Up or call
312 * netif_carrier_off() if current link status is Down.
314 void mii_check_link (struct mii_if_info *mii)
316 int cur_link = mii_link_ok(mii);
317 int prev_link = netif_carrier_ok(mii->dev);
319 if (cur_link && !prev_link)
320 netif_carrier_on(mii->dev);
321 else if (prev_link && !cur_link)
322 netif_carrier_off(mii->dev);
326 * mii_check_media - check the MII interface for a duplex change
327 * @mii: the MII interface
328 * @ok_to_print: OK to print link up/down messages
329 * @init_media: OK to save duplex mode in @mii
331 * Returns 1 if the duplex mode changed, 0 if not.
332 * If the media type is forced, always returns 0.
334 unsigned int mii_check_media (struct mii_if_info *mii,
335 unsigned int ok_to_print,
336 unsigned int init_media)
338 unsigned int old_carrier, new_carrier;
339 int advertise, lpa, media, duplex;
342 /* if forced media, go no further */
343 if (mii->force_media)
344 return 0; /* duplex did not change */
346 /* check current and old link status */
347 old_carrier = netif_carrier_ok(mii->dev) ? 1 : 0;
348 new_carrier = (unsigned int) mii_link_ok(mii);
350 /* if carrier state did not change, this is a "bounce",
351 * just exit as everything is already set correctly
353 if ((!init_media) && (old_carrier == new_carrier))
354 return 0; /* duplex did not change */
356 /* no carrier, nothing much to do */
358 netif_carrier_off(mii->dev);
360 netdev_info(mii->dev, "link down\n");
361 return 0; /* duplex did not change */
365 * we have carrier, see who's on the other end
367 netif_carrier_on(mii->dev);
369 /* get MII advertise and LPA values */
370 if ((!init_media) && (mii->advertising))
371 advertise = mii->advertising;
373 advertise = mii->mdio_read(mii->dev, mii->phy_id, MII_ADVERTISE);
374 mii->advertising = advertise;
376 lpa = mii->mdio_read(mii->dev, mii->phy_id, MII_LPA);
377 if (mii->supports_gmii)
378 lpa2 = mii->mdio_read(mii->dev, mii->phy_id, MII_STAT1000);
380 /* figure out media and duplex from advertise and LPA values */
381 media = mii_nway_result(lpa & advertise);
382 duplex = (media & ADVERTISE_FULL) ? 1 : 0;
383 if (lpa2 & LPA_1000FULL)
387 netdev_info(mii->dev, "link up, %uMbps, %s-duplex, lpa 0x%04X\n",
388 lpa2 & (LPA_1000FULL | LPA_1000HALF) ? 1000 :
389 media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ?
391 duplex ? "full" : "half",
394 if ((init_media) || (mii->full_duplex != duplex)) {
395 mii->full_duplex = duplex;
396 return 1; /* duplex changed */
399 return 0; /* duplex did not change */
403 * generic_mii_ioctl - main MII ioctl interface
404 * @mii_if: the MII interface
405 * @mii_data: MII ioctl data structure
406 * @cmd: MII ioctl command
407 * @duplex_chg_out: pointer to @duplex_changed status if there was no
410 * Returns 0 on success, negative on error.
412 int generic_mii_ioctl(struct mii_if_info *mii_if,
413 struct mii_ioctl_data *mii_data, int cmd,
414 unsigned int *duplex_chg_out)
417 unsigned int duplex_changed = 0;
422 mii_data->phy_id &= mii_if->phy_id_mask;
423 mii_data->reg_num &= mii_if->reg_num_mask;
427 mii_data->phy_id = mii_if->phy_id;
432 mii_if->mdio_read(mii_if->dev, mii_data->phy_id,
437 u16 val = mii_data->val_in;
439 if (mii_data->phy_id == mii_if->phy_id) {
440 switch(mii_data->reg_num) {
442 unsigned int new_duplex = 0;
443 if (val & (BMCR_RESET|BMCR_ANENABLE))
444 mii_if->force_media = 0;
446 mii_if->force_media = 1;
447 if (mii_if->force_media &&
448 (val & BMCR_FULLDPLX))
450 if (mii_if->full_duplex != new_duplex) {
452 mii_if->full_duplex = new_duplex;
457 mii_if->advertising = val;
465 mii_if->mdio_write(mii_if->dev, mii_data->phy_id,
466 mii_data->reg_num, val);
475 if ((rc == 0) && (duplex_chg_out) && (duplex_changed))
481 MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>");
482 MODULE_DESCRIPTION ("MII hardware support library");
483 MODULE_LICENSE("GPL");
485 EXPORT_SYMBOL(mii_link_ok);
486 EXPORT_SYMBOL(mii_nway_restart);
487 EXPORT_SYMBOL(mii_ethtool_gset);
488 EXPORT_SYMBOL(mii_ethtool_sset);
489 EXPORT_SYMBOL(mii_check_link);
490 EXPORT_SYMBOL(mii_check_media);
491 EXPORT_SYMBOL(mii_check_gmii_support);
492 EXPORT_SYMBOL(generic_mii_ioctl);