X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fnet%2Fmii.c;h=210b2b164b303b9283e11c5d7802571f108ef29c;hb=820ae8a80eb59962aefbbd4908dfe144ec0f9edb;hp=2912a34f597bd9316a710eec336ef6c6680af23f;hpb=6aa20a2235535605db6d6d2bd850298b2fe7f31e;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/net/mii.c b/drivers/net/mii.c index 2912a34..210b2b1 100644 --- a/drivers/net/mii.c +++ b/drivers/net/mii.c @@ -31,13 +31,40 @@ #include #include #include -#include +#include +static u32 mii_get_an(struct mii_if_info *mii, u16 addr) +{ + u32 result = 0; + int advert; + + advert = mii->mdio_read(mii->dev, mii->phy_id, addr); + if (advert & LPA_LPACK) + result |= ADVERTISED_Autoneg; + if (advert & ADVERTISE_10HALF) + result |= ADVERTISED_10baseT_Half; + if (advert & ADVERTISE_10FULL) + result |= ADVERTISED_10baseT_Full; + if (advert & ADVERTISE_100HALF) + result |= ADVERTISED_100baseT_Half; + if (advert & ADVERTISE_100FULL) + result |= ADVERTISED_100baseT_Full; + + return result; +} + +/** + * mii_ethtool_gset - get settings that are specified in @ecmd + * @mii: MII interface + * @ecmd: requested ethtool_cmd + * + * Returns 0 for success, negative on error. + */ 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; + u16 bmcr, bmsr, ctrl1000 = 0, stat1000 = 0; + u32 nego; ecmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | @@ -55,50 +82,51 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) /* this isn't fully supported at higher layers */ ecmd->phy_address = mii->phy_id; + ecmd->mdio_support = MDIO_SUPPORTS_C22; 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) - ecmd->advertising |= ADVERTISED_10baseT_Full; - if (advert & ADVERTISE_100HALF) - 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); + bmsr = mii->mdio_read(dev, mii->phy_id, MII_BMSR); if (mii->supports_gmii) { - bmcr2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000); - lpa2 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000); + ctrl1000 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000); + stat1000 = 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 ((bmcr2 & (ADVERTISE_1000HALF | ADVERTISE_1000FULL)) & - (lpa2 >> 2)) + ecmd->advertising |= mii_get_an(mii, MII_ADVERTISE); + if (ctrl1000 & ADVERTISE_1000HALF) + ecmd->advertising |= ADVERTISED_1000baseT_Half; + if (ctrl1000 & ADVERTISE_1000FULL) + ecmd->advertising |= ADVERTISED_1000baseT_Full; + + if (bmsr & BMSR_ANEGCOMPLETE) { + ecmd->lp_advertising = mii_get_an(mii, MII_LPA); + if (stat1000 & LPA_1000HALF) + ecmd->lp_advertising |= + ADVERTISED_1000baseT_Half; + if (stat1000 & LPA_1000FULL) + ecmd->lp_advertising |= + ADVERTISED_1000baseT_Full; + } else { + ecmd->lp_advertising = 0; + } + + nego = ecmd->advertising & ecmd->lp_advertising; + + if (nego & (ADVERTISED_1000baseT_Full | + ADVERTISED_1000baseT_Half)) { ecmd->speed = SPEED_1000; - else if (nego == LPA_100FULL || nego == LPA_100HALF) + ecmd->duplex = !!(nego & ADVERTISED_1000baseT_Full); + } else if (nego & (ADVERTISED_100baseT_Full | + ADVERTISED_100baseT_Half)) { ecmd->speed = SPEED_100; - else - ecmd->speed = SPEED_10; - if ((lpa2 & LPA_1000FULL) || nego == LPA_100FULL || - nego == LPA_10FULL) { - ecmd->duplex = DUPLEX_FULL; - mii->full_duplex = 1; + ecmd->duplex = !!(nego & ADVERTISED_100baseT_Full); } else { - ecmd->duplex = DUPLEX_HALF; - mii->full_duplex = 0; + ecmd->speed = SPEED_10; + ecmd->duplex = !!(nego & ADVERTISED_10baseT_Full); } } else { ecmd->autoneg = AUTONEG_DISABLE; @@ -109,11 +137,20 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; } + mii->full_duplex = ecmd->duplex; + /* ignore maxtxpkt, maxrxpkt for now */ return 0; } +/** + * mii_ethtool_sset - set settings that are specified in @ecmd + * @mii: MII interface + * @ecmd: requested ethtool_cmd + * + * Returns 0 for success, negative on error. + */ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) { struct net_device *dev = mii->dev; @@ -207,6 +244,10 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) return 0; } +/** + * mii_check_gmii_support - check if the MII supports Gb interfaces + * @mii: the MII interface + */ int mii_check_gmii_support(struct mii_if_info *mii) { int reg; @@ -221,6 +262,12 @@ int mii_check_gmii_support(struct mii_if_info *mii) return 0; } +/** + * mii_link_ok - is link status up/ok + * @mii: the MII interface + * + * Returns 1 if the MII reports link status up/ok, 0 otherwise. + */ int mii_link_ok (struct mii_if_info *mii) { /* first, a dummy read, needed to latch some MII phys */ @@ -230,6 +277,12 @@ int mii_link_ok (struct mii_if_info *mii) return 0; } +/** + * mii_nway_restart - restart NWay (autonegotiation) for this interface + * @mii: the MII interface + * + * Returns 0 on success, negative on error. + */ int mii_nway_restart (struct mii_if_info *mii) { int bmcr; @@ -247,6 +300,14 @@ int mii_nway_restart (struct mii_if_info *mii) return r; } +/** + * mii_check_link - check MII link status + * @mii: MII interface + * + * If the link status changed (previous != current), call + * netif_carrier_on() if current link status is Up or call + * netif_carrier_off() if current link status is Down. + */ void mii_check_link (struct mii_if_info *mii) { int cur_link = mii_link_ok(mii); @@ -258,6 +319,15 @@ void mii_check_link (struct mii_if_info *mii) netif_carrier_off(mii->dev); } +/** + * mii_check_media - check the MII interface for a duplex change + * @mii: the MII interface + * @ok_to_print: OK to print link up/down messages + * @init_media: OK to save duplex mode in @mii + * + * Returns 1 if the duplex mode changed, 0 if not. + * If the media type is forced, always returns 0. + */ unsigned int mii_check_media (struct mii_if_info *mii, unsigned int ok_to_print, unsigned int init_media) @@ -326,6 +396,16 @@ unsigned int mii_check_media (struct mii_if_info *mii, return 0; /* duplex did not change */ } +/** + * generic_mii_ioctl - main MII ioctl interface + * @mii_if: the MII interface + * @mii_data: MII ioctl data structure + * @cmd: MII ioctl command + * @duplex_chg_out: pointer to @duplex_changed status if there was no + * ioctl error + * + * Returns 0 on success, negative on error. + */ int generic_mii_ioctl(struct mii_if_info *mii_if, struct mii_ioctl_data *mii_data, int cmd, unsigned int *duplex_chg_out) @@ -353,9 +433,6 @@ int generic_mii_ioctl(struct mii_if_info *mii_if, case SIOCSMIIREG: { u16 val = mii_data->val_in; - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (mii_data->phy_id == mii_if->phy_id) { switch(mii_data->reg_num) { case MII_BMCR: {