diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2009-04-29 04:34:44 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-04-29 20:32:42 -0400 |
commit | 5974700c288aa160fd02b1cb9294173664bcc172 (patch) | |
tree | 063a5bd8637d3ce9f0b829635fe9effd86b22de0 /drivers/net/mii.c | |
parent | 894b19a6b343ce3589237167a56e6df0fe72ef0d (diff) |
mii: Rewrite mii_ethtool_gset() to report mdio_support and lp_advertising
Ignore link partner advertising flags while AN is not complete.
Compile-tested only.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/mii.c')
-rw-r--r-- | drivers/net/mii.c | 91 |
1 files changed, 57 insertions, 34 deletions
diff --git a/drivers/net/mii.c b/drivers/net/mii.c index 92056051f269..d81a5d22a3a9 100644 --- a/drivers/net/mii.c +++ b/drivers/net/mii.c | |||
@@ -31,7 +31,27 @@ | |||
31 | #include <linux/module.h> | 31 | #include <linux/module.h> |
32 | #include <linux/netdevice.h> | 32 | #include <linux/netdevice.h> |
33 | #include <linux/ethtool.h> | 33 | #include <linux/ethtool.h> |
34 | #include <linux/mii.h> | 34 | #include <linux/mdio.h> |
35 | |||
36 | static u32 mii_get_an(struct mii_if_info *mii, u16 addr) | ||
37 | { | ||
38 | u32 result = 0; | ||
39 | int advert; | ||
40 | |||
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; | ||
52 | |||
53 | return result; | ||
54 | } | ||
35 | 55 | ||
36 | /** | 56 | /** |
37 | * mii_ethtool_gset - get settings that are specified in @ecmd | 57 | * mii_ethtool_gset - get settings that are specified in @ecmd |
@@ -43,8 +63,8 @@ | |||
43 | int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) | 63 | int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) |
44 | { | 64 | { |
45 | struct net_device *dev = mii->dev; | 65 | struct net_device *dev = mii->dev; |
46 | u32 advert, bmcr, lpa, nego; | 66 | u16 bmcr, bmsr, ctrl1000 = 0, stat1000 = 0; |
47 | u32 advert2 = 0, bmcr2 = 0, lpa2 = 0; | 67 | u32 nego; |
48 | 68 | ||
49 | ecmd->supported = | 69 | ecmd->supported = |
50 | (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | | 70 | (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | |
@@ -62,50 +82,51 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) | |||
62 | 82 | ||
63 | /* this isn't fully supported at higher layers */ | 83 | /* this isn't fully supported at higher layers */ |
64 | ecmd->phy_address = mii->phy_id; | 84 | ecmd->phy_address = mii->phy_id; |
85 | ecmd->mdio_support = MDIO_SUPPORTS_C22; | ||
65 | 86 | ||
66 | ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII; | 87 | ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII; |
67 | advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE); | ||
68 | if (mii->supports_gmii) | ||
69 | advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000); | ||
70 | |||
71 | if (advert & ADVERTISE_10HALF) | ||
72 | ecmd->advertising |= ADVERTISED_10baseT_Half; | ||
73 | if (advert & ADVERTISE_10FULL) | ||
74 | ecmd->advertising |= ADVERTISED_10baseT_Full; | ||
75 | if (advert & ADVERTISE_100HALF) | ||
76 | ecmd->advertising |= ADVERTISED_100baseT_Half; | ||
77 | if (advert & ADVERTISE_100FULL) | ||
78 | ecmd->advertising |= ADVERTISED_100baseT_Full; | ||
79 | if (advert2 & ADVERTISE_1000HALF) | ||
80 | ecmd->advertising |= ADVERTISED_1000baseT_Half; | ||
81 | if (advert2 & ADVERTISE_1000FULL) | ||
82 | ecmd->advertising |= ADVERTISED_1000baseT_Full; | ||
83 | 88 | ||
84 | bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR); | 89 | bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR); |
85 | lpa = mii->mdio_read(dev, mii->phy_id, MII_LPA); | 90 | bmsr = mii->mdio_read(dev, mii->phy_id, MII_BMSR); |
86 | if (mii->supports_gmii) { | 91 | if (mii->supports_gmii) { |
87 | bmcr2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000); | 92 | ctrl1000 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000); |
88 | lpa2 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000); | 93 | stat1000 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000); |
89 | } | 94 | } |
90 | if (bmcr & BMCR_ANENABLE) { | 95 | if (bmcr & BMCR_ANENABLE) { |
91 | ecmd->advertising |= ADVERTISED_Autoneg; | 96 | ecmd->advertising |= ADVERTISED_Autoneg; |
92 | ecmd->autoneg = AUTONEG_ENABLE; | 97 | ecmd->autoneg = AUTONEG_ENABLE; |
93 | 98 | ||
94 | nego = mii_nway_result(advert & lpa); | 99 | ecmd->advertising |= mii_get_an(mii, MII_ADVERTISE); |
95 | if ((bmcr2 & (ADVERTISE_1000HALF | ADVERTISE_1000FULL)) & | 100 | if (ctrl1000 & ADVERTISE_1000HALF) |
96 | (lpa2 >> 2)) | 101 | ecmd->advertising |= ADVERTISED_1000baseT_Half; |
102 | if (ctrl1000 & ADVERTISE_1000FULL) | ||
103 | ecmd->advertising |= ADVERTISED_1000baseT_Full; | ||
104 | |||
105 | if (bmsr & BMSR_ANEGCOMPLETE) { | ||
106 | ecmd->lp_advertising = mii_get_an(mii, MII_LPA); | ||
107 | if (stat1000 & LPA_1000HALF) | ||
108 | ecmd->lp_advertising |= | ||
109 | ADVERTISED_1000baseT_Half; | ||
110 | if (stat1000 & LPA_1000FULL) | ||
111 | ecmd->lp_advertising |= | ||
112 | ADVERTISED_1000baseT_Full; | ||
113 | } else { | ||
114 | ecmd->lp_advertising = 0; | ||
115 | } | ||
116 | |||
117 | nego = ecmd->advertising & ecmd->lp_advertising; | ||
118 | |||
119 | if (nego & (ADVERTISED_1000baseT_Full | | ||
120 | ADVERTISED_1000baseT_Half)) { | ||
97 | ecmd->speed = SPEED_1000; | 121 | ecmd->speed = SPEED_1000; |
98 | else if (nego == LPA_100FULL || nego == LPA_100HALF) | 122 | ecmd->duplex = !!(nego & ADVERTISED_1000baseT_Full); |
123 | } else if (nego & (ADVERTISED_100baseT_Full | | ||
124 | ADVERTISED_100baseT_Half)) { | ||
99 | ecmd->speed = SPEED_100; | 125 | ecmd->speed = SPEED_100; |
100 | else | 126 | ecmd->duplex = !!(nego & ADVERTISED_100baseT_Full); |
101 | ecmd->speed = SPEED_10; | ||
102 | if ((lpa2 & LPA_1000FULL) || nego == LPA_100FULL || | ||
103 | nego == LPA_10FULL) { | ||
104 | ecmd->duplex = DUPLEX_FULL; | ||
105 | mii->full_duplex = 1; | ||
106 | } else { | 127 | } else { |
107 | ecmd->duplex = DUPLEX_HALF; | 128 | ecmd->speed = SPEED_10; |
108 | mii->full_duplex = 0; | 129 | ecmd->duplex = !!(nego & ADVERTISED_10baseT_Full); |
109 | } | 130 | } |
110 | } else { | 131 | } else { |
111 | ecmd->autoneg = AUTONEG_DISABLE; | 132 | ecmd->autoneg = AUTONEG_DISABLE; |
@@ -116,6 +137,8 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) | |||
116 | ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; | 137 | ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; |
117 | } | 138 | } |
118 | 139 | ||
140 | mii->full_duplex = ecmd->duplex; | ||
141 | |||
119 | /* ignore maxtxpkt, maxrxpkt for now */ | 142 | /* ignore maxtxpkt, maxrxpkt for now */ |
120 | 143 | ||
121 | return 0; | 144 | return 0; |