X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fnet%2Fmii.c;h=2912a34f597bd9316a710eec336ef6c6680af23f;hb=refs%2Fheads%2Fvserver;hp=3de5e46045d6c1a734a687b16da59f64a75f024c;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/net/mii.c b/drivers/net/mii.c index 3de5e4604..2912a34f5 100644 --- a/drivers/net/mii.c +++ b/drivers/net/mii.c @@ -37,11 +37,15 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) { struct net_device *dev = mii->dev; u32 advert, bmcr, lpa, nego; + u32 advert2 = 0, bmcr2 = 0, lpa2 = 0; ecmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII); + if (mii->supports_gmii) + ecmd->supported |= SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full; /* only supports twisted-pair */ ecmd->port = PORT_MII; @@ -54,6 +58,9 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII; advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE); + if (mii->supports_gmii) + advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000); + if (advert & ADVERTISE_10HALF) ecmd->advertising |= ADVERTISED_10baseT_Half; if (advert & ADVERTISE_10FULL) @@ -62,19 +69,31 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) ecmd->advertising |= ADVERTISED_100baseT_Half; if (advert & ADVERTISE_100FULL) ecmd->advertising |= ADVERTISED_100baseT_Full; + if (advert2 & ADVERTISE_1000HALF) + ecmd->advertising |= ADVERTISED_1000baseT_Half; + if (advert2 & ADVERTISE_1000FULL) + ecmd->advertising |= ADVERTISED_1000baseT_Full; bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR); lpa = mii->mdio_read(dev, mii->phy_id, MII_LPA); + if (mii->supports_gmii) { + bmcr2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000); + lpa2 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000); + } if (bmcr & BMCR_ANENABLE) { ecmd->advertising |= ADVERTISED_Autoneg; ecmd->autoneg = AUTONEG_ENABLE; - + nego = mii_nway_result(advert & lpa); - if (nego == LPA_100FULL || nego == LPA_100HALF) + if ((bmcr2 & (ADVERTISE_1000HALF | ADVERTISE_1000FULL)) & + (lpa2 >> 2)) + ecmd->speed = SPEED_1000; + else if (nego == LPA_100FULL || nego == LPA_100HALF) ecmd->speed = SPEED_100; else ecmd->speed = SPEED_10; - if (nego == LPA_100FULL || nego == LPA_10FULL) { + if ((lpa2 & LPA_1000FULL) || nego == LPA_100FULL || + nego == LPA_10FULL) { ecmd->duplex = DUPLEX_FULL; mii->full_duplex = 1; } else { @@ -84,7 +103,9 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) } else { ecmd->autoneg = AUTONEG_DISABLE; - ecmd->speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10; + ecmd->speed = ((bmcr & BMCR_SPEED1000 && + (bmcr & BMCR_SPEED100) == 0) ? SPEED_1000 : + (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10); ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; } @@ -97,7 +118,9 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) { struct net_device *dev = mii->dev; - if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100) + if (ecmd->speed != SPEED_10 && + ecmd->speed != SPEED_100 && + ecmd->speed != SPEED_1000) return -EINVAL; if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) return -EINVAL; @@ -109,21 +132,30 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) return -EINVAL; if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE) return -EINVAL; - + if ((ecmd->speed == SPEED_1000) && (!mii->supports_gmii)) + return -EINVAL; + /* ignore supported, maxtxpkt, maxrxpkt */ - + if (ecmd->autoneg == AUTONEG_ENABLE) { u32 bmcr, advert, tmp; + u32 advert2 = 0, tmp2 = 0; if ((ecmd->advertising & (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half | - ADVERTISED_100baseT_Full)) == 0) + ADVERTISED_100baseT_Full | + ADVERTISED_1000baseT_Half | + ADVERTISED_1000baseT_Full)) == 0) return -EINVAL; /* advertise only what has been requested */ advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE); tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4); + if (mii->supports_gmii) { + advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000); + tmp2 = advert2 & ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL); + } if (ecmd->advertising & ADVERTISED_10baseT_Half) tmp |= ADVERTISE_10HALF; if (ecmd->advertising & ADVERTISED_10baseT_Full) @@ -132,11 +164,19 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) tmp |= ADVERTISE_100HALF; if (ecmd->advertising & ADVERTISED_100baseT_Full) tmp |= ADVERTISE_100FULL; + if (mii->supports_gmii) { + if (ecmd->advertising & ADVERTISED_1000baseT_Half) + tmp2 |= ADVERTISE_1000HALF; + if (ecmd->advertising & ADVERTISED_1000baseT_Full) + tmp2 |= ADVERTISE_1000FULL; + } if (advert != tmp) { mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp); mii->advertising = tmp; } - + if ((mii->supports_gmii) && (advert2 != tmp2)) + mii->mdio_write(dev, mii->phy_id, MII_CTRL1000, tmp2); + /* turn on autonegotiation, and force a renegotiate */ bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR); bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); @@ -148,8 +188,11 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) /* turn off auto negotiation, set speed and duplexity */ bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR); - tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX); - if (ecmd->speed == SPEED_100) + tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | + BMCR_SPEED1000 | BMCR_FULLDPLX); + if (ecmd->speed == SPEED_1000) + tmp |= BMCR_SPEED1000; + else if (ecmd->speed == SPEED_100) tmp |= BMCR_SPEED100; if (ecmd->duplex == DUPLEX_FULL) { tmp |= BMCR_FULLDPLX; @@ -164,6 +207,20 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) return 0; } +int mii_check_gmii_support(struct mii_if_info *mii) +{ + int reg; + + reg = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR); + if (reg & BMSR_ESTATEN) { + reg = mii->mdio_read(mii->dev, mii->phy_id, MII_ESTATUS); + if (reg & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF)) + return 1; + } + + return 0; +} + int mii_link_ok (struct mii_if_info *mii) { /* first, a dummy read, needed to latch some MII phys */ @@ -207,6 +264,7 @@ unsigned int mii_check_media (struct mii_if_info *mii, { unsigned int old_carrier, new_carrier; int advertise, lpa, media, duplex; + int lpa2 = 0; /* if forced media, go no further */ if (mii->force_media) @@ -243,16 +301,20 @@ unsigned int mii_check_media (struct mii_if_info *mii, mii->advertising = advertise; } lpa = mii->mdio_read(mii->dev, mii->phy_id, MII_LPA); + if (mii->supports_gmii) + lpa2 = mii->mdio_read(mii->dev, mii->phy_id, MII_STAT1000); /* figure out media and duplex from advertise and LPA values */ media = mii_nway_result(lpa & advertise); duplex = (media & ADVERTISE_FULL) ? 1 : 0; + if (lpa2 & LPA_1000FULL) + duplex = 1; if (ok_to_print) printk(KERN_INFO "%s: link up, %sMbps, %s-duplex, lpa 0x%04X\n", mii->dev->name, - media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ? - "100" : "10", + lpa2 & (LPA_1000FULL | LPA_1000HALF) ? "1000" : + media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ? "100" : "10", duplex ? "full" : "half", lpa); @@ -346,5 +408,6 @@ EXPORT_SYMBOL(mii_ethtool_gset); EXPORT_SYMBOL(mii_ethtool_sset); EXPORT_SYMBOL(mii_check_link); EXPORT_SYMBOL(mii_check_media); +EXPORT_SYMBOL(mii_check_gmii_support); EXPORT_SYMBOL(generic_mii_ioctl);