aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/mii.c
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2009-04-29 04:34:44 -0400
committerDavid S. Miller <davem@davemloft.net>2009-04-29 20:32:42 -0400
commit5974700c288aa160fd02b1cb9294173664bcc172 (patch)
tree063a5bd8637d3ce9f0b829635fe9effd86b22de0 /drivers/net/mii.c
parent894b19a6b343ce3589237167a56e6df0fe72ef0d (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.c91
1 files changed, 57 insertions, 34 deletions
diff --git a/drivers/net/mii.c b/drivers/net/mii.c
index 92056051f26..d81a5d22a3a 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
36static 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 @@
43int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) 63int 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;