ethtool/mdio: Report MDIO mode support and link partner advertising
Ben Hutchings [Wed, 29 Apr 2009 08:21:53 +0000 (08:21 +0000)]
Add mdio_support and lp_advertising fields to ethtool_cmd.  Set these
in mdio45_ethtool_gset{,_npage}().

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

drivers/net/mdio.c
include/linux/ethtool.h
include/linux/mdio.h

index 2fb0d16..ee383c2 100644 (file)
@@ -173,6 +173,8 @@ void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio,
 
        ecmd->transceiver = XCVR_INTERNAL;
        ecmd->phy_address = mdio->prtad;
+       ecmd->mdio_support =
+               mdio->mode_support & (MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22);
 
        reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD,
                              MDIO_CTRL2);
@@ -235,16 +237,19 @@ void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio,
 
        if (ecmd->autoneg) {
                u32 modes = 0;
+               int an_stat = mdio->mdio_read(mdio->dev, mdio->prtad,
+                                             MDIO_MMD_AN, MDIO_STAT1);
 
                /* If AN is complete and successful, report best common
                 * mode, otherwise report best advertised mode. */
-               if (mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_AN,
-                                   MDIO_STAT1) &
-                   MDIO_AN_STAT1_COMPLETE)
-                       modes = (ecmd->advertising &
-                                (mdio45_get_an(mdio, MDIO_AN_LPA) |
-                                 npage_lpa));
-               if (modes == 0)
+               if (an_stat & MDIO_AN_STAT1_COMPLETE) {
+                       ecmd->lp_advertising =
+                               mdio45_get_an(mdio, MDIO_AN_LPA) | npage_lpa;
+                       if (an_stat & MDIO_AN_STAT1_LPABLE)
+                               ecmd->lp_advertising |= ADVERTISED_Autoneg;
+                       modes = ecmd->advertising & ecmd->lp_advertising;
+               }
+               if ((modes & ~ADVERTISED_Autoneg) == 0)
                        modes = ecmd->advertising;
 
                if (modes & ADVERTISED_10000baseT_Full) {
index 5ccb6bd..14e6bc8 100644 (file)
@@ -26,11 +26,13 @@ struct ethtool_cmd {
        __u8    phy_address;
        __u8    transceiver;    /* Which transceiver to use */
        __u8    autoneg;        /* Enable or disable autonegotiation */
+       __u8    mdio_support;
        __u32   maxtxpkt;       /* Tx pkts before generating tx int */
        __u32   maxrxpkt;       /* Rx pkts before generating rx int */
        __u16   speed_hi;
        __u16   reserved2;
-       __u32   reserved[3];
+       __u32   lp_advertising; /* Features the link partner advertises */
+       __u32   reserved[2];
 };
 
 static inline void ethtool_cmd_speed_set(struct ethtool_cmd *ep,
index 5645c0f..1bff2f2 100644 (file)
@@ -234,6 +234,9 @@ static inline __u16 mdio_phy_id_devad(int phy_id)
        return phy_id & MDIO_PHY_ID_DEVAD;
 }
 
+#define MDIO_SUPPORTS_C22              1
+#define MDIO_SUPPORTS_C45              2
+
 #ifdef __KERNEL__ 
 
 /**
@@ -264,8 +267,6 @@ struct mdio_if_info {
 
 #define MDIO_PRTAD_NONE                        (-1)
 #define MDIO_DEVAD_NONE                        (-1)
-#define MDIO_SUPPORTS_C22              1
-#define MDIO_SUPPORTS_C45              2
 #define MDIO_EMULATE_C22               4
 
 struct ethtool_cmd;