vserver 2.0 rc7
[linux-2.6.git] / drivers / net / mii.c
index 3de5e46..c33cb3d 100644 (file)
@@ -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,10 +164,18 @@ 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);
@@ -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;
@@ -207,6 +250,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 +287,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);