3 mii.c: MII interface library
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
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;
45 return result | mii_adv_to_ethtool_100bt(advert);
49 * mii_ethtool_gset - get settings that are specified in @ecmd
51 * @ecmd: requested ethtool_cmd
53 * The @ecmd parameter is expected to have been cleared before calling
56 * Returns 0 for success, negative on error.
58 int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
60 struct net_device *dev = mii->dev;
61 u16 bmcr, bmsr, ctrl1000 = 0, stat1000 = 0;
65 (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
66 SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
67 SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
68 if (mii->supports_gmii)
69 ecmd->supported |= SUPPORTED_1000baseT_Half |
70 SUPPORTED_1000baseT_Full;
72 /* only supports twisted-pair */
73 ecmd->port = PORT_MII;
75 /* only supports internal transceiver */
76 ecmd->transceiver = XCVR_INTERNAL;
78 /* this isn't fully supported at higher layers */
79 ecmd->phy_address = mii->phy_id;
80 ecmd->mdio_support = MDIO_SUPPORTS_C22;
82 ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
84 bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
85 bmsr = mii->mdio_read(dev, mii->phy_id, MII_BMSR);
86 if (mii->supports_gmii) {
87 ctrl1000 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
88 stat1000 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000);
90 if (bmcr & BMCR_ANENABLE) {
91 ecmd->advertising |= ADVERTISED_Autoneg;
92 ecmd->autoneg = AUTONEG_ENABLE;
94 ecmd->advertising |= mii_get_an(mii, MII_ADVERTISE);
95 if (mii->supports_gmii)
96 ecmd->advertising |= mii_adv_to_ethtool_1000T(ctrl1000);
98 if (bmsr & BMSR_ANEGCOMPLETE) {
99 ecmd->lp_advertising = mii_get_an(mii, MII_LPA);
100 ecmd->lp_advertising |=
101 mii_lpa_to_ethtool_1000T(stat1000);
103 ecmd->lp_advertising = 0;
106 nego = ecmd->advertising & ecmd->lp_advertising;
108 if (nego & (ADVERTISED_1000baseT_Full |
109 ADVERTISED_1000baseT_Half)) {
110 ethtool_cmd_speed_set(ecmd, SPEED_1000);
111 ecmd->duplex = !!(nego & ADVERTISED_1000baseT_Full);
112 } else if (nego & (ADVERTISED_100baseT_Full |
113 ADVERTISED_100baseT_Half)) {
114 ethtool_cmd_speed_set(ecmd, SPEED_100);
115 ecmd->duplex = !!(nego & ADVERTISED_100baseT_Full);
117 ethtool_cmd_speed_set(ecmd, SPEED_10);
118 ecmd->duplex = !!(nego & ADVERTISED_10baseT_Full);
121 ecmd->autoneg = AUTONEG_DISABLE;
123 ethtool_cmd_speed_set(ecmd,
124 ((bmcr & BMCR_SPEED1000 &&
125 (bmcr & BMCR_SPEED100) == 0) ?
127 ((bmcr & BMCR_SPEED100) ?
128 SPEED_100 : SPEED_10)));
129 ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
132 mii->full_duplex = ecmd->duplex;
134 /* ignore maxtxpkt, maxrxpkt for now */
140 * mii_ethtool_sset - set settings that are specified in @ecmd
141 * @mii: MII interface
142 * @ecmd: requested ethtool_cmd
144 * Returns 0 for success, negative on error.
146 int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
148 struct net_device *dev = mii->dev;
149 u32 speed = ethtool_cmd_speed(ecmd);
151 if (speed != SPEED_10 &&
152 speed != SPEED_100 &&
155 if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
157 if (ecmd->port != PORT_MII)
159 if (ecmd->transceiver != XCVR_INTERNAL)
161 if (ecmd->phy_address != mii->phy_id)
163 if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
165 if ((speed == SPEED_1000) && (!mii->supports_gmii))
168 /* ignore supported, maxtxpkt, maxrxpkt */
170 if (ecmd->autoneg == AUTONEG_ENABLE) {
171 u32 bmcr, advert, tmp;
172 u32 advert2 = 0, tmp2 = 0;
174 if ((ecmd->advertising & (ADVERTISED_10baseT_Half |
175 ADVERTISED_10baseT_Full |
176 ADVERTISED_100baseT_Half |
177 ADVERTISED_100baseT_Full |
178 ADVERTISED_1000baseT_Half |
179 ADVERTISED_1000baseT_Full)) == 0)
182 /* advertise only what has been requested */
183 advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
184 tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
185 if (mii->supports_gmii) {
186 advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
187 tmp2 = advert2 & ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
189 tmp |= ethtool_adv_to_mii_100bt(ecmd->advertising);
191 if (mii->supports_gmii)
192 tmp2 |= ethtool_adv_to_mii_1000T(ecmd->advertising);
194 mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
195 mii->advertising = tmp;
197 if ((mii->supports_gmii) && (advert2 != tmp2))
198 mii->mdio_write(dev, mii->phy_id, MII_CTRL1000, tmp2);
200 /* turn on autonegotiation, and force a renegotiate */
201 bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
202 bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
203 mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
205 mii->force_media = 0;
209 /* turn off auto negotiation, set speed and duplexity */
210 bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
211 tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
212 BMCR_SPEED1000 | BMCR_FULLDPLX);
213 if (speed == SPEED_1000)
214 tmp |= BMCR_SPEED1000;
215 else if (speed == SPEED_100)
216 tmp |= BMCR_SPEED100;
217 if (ecmd->duplex == DUPLEX_FULL) {
218 tmp |= BMCR_FULLDPLX;
219 mii->full_duplex = 1;
221 mii->full_duplex = 0;
223 mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp);
225 mii->force_media = 1;
231 * mii_check_gmii_support - check if the MII supports Gb interfaces
232 * @mii: the MII interface
234 int mii_check_gmii_support(struct mii_if_info *mii)
238 reg = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
239 if (reg & BMSR_ESTATEN) {
240 reg = mii->mdio_read(mii->dev, mii->phy_id, MII_ESTATUS);
241 if (reg & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF))
249 * mii_link_ok - is link status up/ok
250 * @mii: the MII interface
252 * Returns 1 if the MII reports link status up/ok, 0 otherwise.
254 int mii_link_ok (struct mii_if_info *mii)
256 /* first, a dummy read, needed to latch some MII phys */
257 mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
258 if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS)
264 * mii_nway_restart - restart NWay (autonegotiation) for this interface
265 * @mii: the MII interface
267 * Returns 0 on success, negative on error.
269 int mii_nway_restart (struct mii_if_info *mii)
274 /* if autoneg is off, it's an error */
275 bmcr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR);
277 if (bmcr & BMCR_ANENABLE) {
278 bmcr |= BMCR_ANRESTART;
279 mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, bmcr);
287 * mii_check_link - check MII link status
288 * @mii: MII interface
290 * If the link status changed (previous != current), call
291 * netif_carrier_on() if current link status is Up or call
292 * netif_carrier_off() if current link status is Down.
294 void mii_check_link (struct mii_if_info *mii)
296 int cur_link = mii_link_ok(mii);
297 int prev_link = netif_carrier_ok(mii->dev);
299 if (cur_link && !prev_link)
300 netif_carrier_on(mii->dev);
301 else if (prev_link && !cur_link)
302 netif_carrier_off(mii->dev);
306 * mii_check_media - check the MII interface for a duplex change
307 * @mii: the MII interface
308 * @ok_to_print: OK to print link up/down messages
309 * @init_media: OK to save duplex mode in @mii
311 * Returns 1 if the duplex mode changed, 0 if not.
312 * If the media type is forced, always returns 0.
314 unsigned int mii_check_media (struct mii_if_info *mii,
315 unsigned int ok_to_print,
316 unsigned int init_media)
318 unsigned int old_carrier, new_carrier;
319 int advertise, lpa, media, duplex;
322 /* if forced media, go no further */
323 if (mii->force_media)
324 return 0; /* duplex did not change */
326 /* check current and old link status */
327 old_carrier = netif_carrier_ok(mii->dev) ? 1 : 0;
328 new_carrier = (unsigned int) mii_link_ok(mii);
330 /* if carrier state did not change, this is a "bounce",
331 * just exit as everything is already set correctly
333 if ((!init_media) && (old_carrier == new_carrier))
334 return 0; /* duplex did not change */
336 /* no carrier, nothing much to do */
338 netif_carrier_off(mii->dev);
340 netdev_info(mii->dev, "link down\n");
341 return 0; /* duplex did not change */
345 * we have carrier, see who's on the other end
347 netif_carrier_on(mii->dev);
349 /* get MII advertise and LPA values */
350 if ((!init_media) && (mii->advertising))
351 advertise = mii->advertising;
353 advertise = mii->mdio_read(mii->dev, mii->phy_id, MII_ADVERTISE);
354 mii->advertising = advertise;
356 lpa = mii->mdio_read(mii->dev, mii->phy_id, MII_LPA);
357 if (mii->supports_gmii)
358 lpa2 = mii->mdio_read(mii->dev, mii->phy_id, MII_STAT1000);
360 /* figure out media and duplex from advertise and LPA values */
361 media = mii_nway_result(lpa & advertise);
362 duplex = (media & ADVERTISE_FULL) ? 1 : 0;
363 if (lpa2 & LPA_1000FULL)
367 netdev_info(mii->dev, "link up, %uMbps, %s-duplex, lpa 0x%04X\n",
368 lpa2 & (LPA_1000FULL | LPA_1000HALF) ? 1000 :
369 media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ?
371 duplex ? "full" : "half",
374 if ((init_media) || (mii->full_duplex != duplex)) {
375 mii->full_duplex = duplex;
376 return 1; /* duplex changed */
379 return 0; /* duplex did not change */
383 * generic_mii_ioctl - main MII ioctl interface
384 * @mii_if: the MII interface
385 * @mii_data: MII ioctl data structure
386 * @cmd: MII ioctl command
387 * @duplex_chg_out: pointer to @duplex_changed status if there was no
390 * Returns 0 on success, negative on error.
392 int generic_mii_ioctl(struct mii_if_info *mii_if,
393 struct mii_ioctl_data *mii_data, int cmd,
394 unsigned int *duplex_chg_out)
397 unsigned int duplex_changed = 0;
402 mii_data->phy_id &= mii_if->phy_id_mask;
403 mii_data->reg_num &= mii_if->reg_num_mask;
407 mii_data->phy_id = mii_if->phy_id;
412 mii_if->mdio_read(mii_if->dev, mii_data->phy_id,
417 u16 val = mii_data->val_in;
419 if (mii_data->phy_id == mii_if->phy_id) {
420 switch(mii_data->reg_num) {
422 unsigned int new_duplex = 0;
423 if (val & (BMCR_RESET|BMCR_ANENABLE))
424 mii_if->force_media = 0;
426 mii_if->force_media = 1;
427 if (mii_if->force_media &&
428 (val & BMCR_FULLDPLX))
430 if (mii_if->full_duplex != new_duplex) {
432 mii_if->full_duplex = new_duplex;
437 mii_if->advertising = val;
445 mii_if->mdio_write(mii_if->dev, mii_data->phy_id,
446 mii_data->reg_num, val);
455 if ((rc == 0) && (duplex_chg_out) && (duplex_changed))
462 MODULE_DESCRIPTION ("MII hardware support library");
463 MODULE_LICENSE("GPL");
465 EXPORT_SYMBOL(mii_link_ok);
466 EXPORT_SYMBOL(mii_nway_restart);
467 EXPORT_SYMBOL(mii_ethtool_gset);
468 EXPORT_SYMBOL(mii_ethtool_sset);
469 EXPORT_SYMBOL(mii_check_link);
470 EXPORT_SYMBOL(mii_check_media);
471 EXPORT_SYMBOL(mii_check_gmii_support);
472 EXPORT_SYMBOL(generic_mii_ioctl);