diff options
-rw-r--r-- | drivers/net/ethernet/dec/tulip/de2104x.c | 91 | ||||
-rw-r--r-- | drivers/net/ethernet/dec/tulip/uli526x.c | 41 | ||||
-rw-r--r-- | drivers/net/ethernet/dec/tulip/winbond-840.c | 14 | ||||
-rw-r--r-- | drivers/net/ethernet/dlink/dl2k.c | 71 | ||||
-rw-r--r-- | drivers/net/ethernet/dlink/sundance.c | 14 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_ethtool.c | 73 | ||||
-rw-r--r-- | drivers/net/ethernet/faraday/ftmac100.c | 14 | ||||
-rw-r--r-- | drivers/net/ethernet/fealnx.c | 14 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/falcon/efx.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/falcon/ethtool.c | 29 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/falcon/mdio_10g.c | 44 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/falcon/mdio_10g.h | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/falcon/net_driver.h | 12 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/falcon/qt202x_phy.c | 9 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/falcon/tenxpress.c | 22 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/falcon/txc43128_phy.c | 9 | ||||
-rw-r--r-- | drivers/net/mdio.c | 178 | ||||
-rw-r--r-- | include/linux/mdio.h | 21 |
18 files changed, 455 insertions, 206 deletions
diff --git a/drivers/net/ethernet/dec/tulip/de2104x.c b/drivers/net/ethernet/dec/tulip/de2104x.c index 57c17e797ae3..127ce9707378 100644 --- a/drivers/net/ethernet/dec/tulip/de2104x.c +++ b/drivers/net/ethernet/dec/tulip/de2104x.c @@ -1485,95 +1485,104 @@ static void __de_get_regs(struct de_private *de, u8 *buf) de_rx_missed(de, rbuf[8]); } -static int __de_get_settings(struct de_private *de, struct ethtool_cmd *ecmd) +static int __de_get_link_ksettings(struct de_private *de, + struct ethtool_link_ksettings *cmd) { - ecmd->supported = de->media_supported; - ecmd->transceiver = XCVR_INTERNAL; - ecmd->phy_address = 0; - ecmd->advertising = de->media_advertise; + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, + de->media_supported); + cmd->base.phy_address = 0; + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising, + de->media_advertise); switch (de->media_type) { case DE_MEDIA_AUI: - ecmd->port = PORT_AUI; + cmd->base.port = PORT_AUI; break; case DE_MEDIA_BNC: - ecmd->port = PORT_BNC; + cmd->base.port = PORT_BNC; break; default: - ecmd->port = PORT_TP; + cmd->base.port = PORT_TP; break; } - ethtool_cmd_speed_set(ecmd, 10); + cmd->base.speed = 10; if (dr32(MacMode) & FullDuplex) - ecmd->duplex = DUPLEX_FULL; + cmd->base.duplex = DUPLEX_FULL; else - ecmd->duplex = DUPLEX_HALF; + cmd->base.duplex = DUPLEX_HALF; if (de->media_lock) - ecmd->autoneg = AUTONEG_DISABLE; + cmd->base.autoneg = AUTONEG_DISABLE; else - ecmd->autoneg = AUTONEG_ENABLE; + cmd->base.autoneg = AUTONEG_ENABLE; /* ignore maxtxpkt, maxrxpkt for now */ return 0; } -static int __de_set_settings(struct de_private *de, struct ethtool_cmd *ecmd) +static int __de_set_link_ksettings(struct de_private *de, + const struct ethtool_link_ksettings *cmd) { u32 new_media; unsigned int media_lock; + u8 duplex = cmd->base.duplex; + u8 port = cmd->base.port; + u8 autoneg = cmd->base.autoneg; + u32 advertising; - if (ethtool_cmd_speed(ecmd) != 10) - return -EINVAL; - if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) + ethtool_convert_link_mode_to_legacy_u32(&advertising, + cmd->link_modes.advertising); + + if (cmd->base.speed != 10) return -EINVAL; - if (ecmd->port != PORT_TP && ecmd->port != PORT_AUI && ecmd->port != PORT_BNC) + if (duplex != DUPLEX_HALF && duplex != DUPLEX_FULL) return -EINVAL; - if (de->de21040 && ecmd->port == PORT_BNC) + if (port != PORT_TP && port != PORT_AUI && port != PORT_BNC) return -EINVAL; - if (ecmd->transceiver != XCVR_INTERNAL) + if (de->de21040 && port == PORT_BNC) return -EINVAL; - if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE) + if (autoneg != AUTONEG_DISABLE && autoneg != AUTONEG_ENABLE) return -EINVAL; - if (ecmd->advertising & ~de->media_supported) + if (advertising & ~de->media_supported) return -EINVAL; - if (ecmd->autoneg == AUTONEG_ENABLE && - (!(ecmd->advertising & ADVERTISED_Autoneg))) + if (autoneg == AUTONEG_ENABLE && + (!(advertising & ADVERTISED_Autoneg))) return -EINVAL; - switch (ecmd->port) { + switch (port) { case PORT_AUI: new_media = DE_MEDIA_AUI; - if (!(ecmd->advertising & ADVERTISED_AUI)) + if (!(advertising & ADVERTISED_AUI)) return -EINVAL; break; case PORT_BNC: new_media = DE_MEDIA_BNC; - if (!(ecmd->advertising & ADVERTISED_BNC)) + if (!(advertising & ADVERTISED_BNC)) return -EINVAL; break; default: - if (ecmd->autoneg == AUTONEG_ENABLE) + if (autoneg == AUTONEG_ENABLE) new_media = DE_MEDIA_TP_AUTO; - else if (ecmd->duplex == DUPLEX_FULL) + else if (duplex == DUPLEX_FULL) new_media = DE_MEDIA_TP_FD; else new_media = DE_MEDIA_TP; - if (!(ecmd->advertising & ADVERTISED_TP)) + if (!(advertising & ADVERTISED_TP)) return -EINVAL; - if (!(ecmd->advertising & (ADVERTISED_10baseT_Full | ADVERTISED_10baseT_Half))) + if (!(advertising & (ADVERTISED_10baseT_Full | + ADVERTISED_10baseT_Half))) return -EINVAL; break; } - media_lock = (ecmd->autoneg == AUTONEG_ENABLE) ? 0 : 1; + media_lock = (autoneg == AUTONEG_ENABLE) ? 0 : 1; if ((new_media == de->media_type) && (media_lock == de->media_lock) && - (ecmd->advertising == de->media_advertise)) + (advertising == de->media_advertise)) return 0; /* nothing to change */ de_link_down(de); @@ -1582,7 +1591,7 @@ static int __de_set_settings(struct de_private *de, struct ethtool_cmd *ecmd) de->media_type = new_media; de->media_lock = media_lock; - de->media_advertise = ecmd->advertising; + de->media_advertise = advertising; de_set_media(de); if (netif_running(de->dev)) de_start_rxtx(de); @@ -1604,25 +1613,27 @@ static int de_get_regs_len(struct net_device *dev) return DE_REGS_SIZE; } -static int de_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) +static int de_get_link_ksettings(struct net_device *dev, + struct ethtool_link_ksettings *cmd) { struct de_private *de = netdev_priv(dev); int rc; spin_lock_irq(&de->lock); - rc = __de_get_settings(de, ecmd); + rc = __de_get_link_ksettings(de, cmd); spin_unlock_irq(&de->lock); return rc; } -static int de_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) +static int de_set_link_ksettings(struct net_device *dev, + const struct ethtool_link_ksettings *cmd) { struct de_private *de = netdev_priv(dev); int rc; spin_lock_irq(&de->lock); - rc = __de_set_settings(de, ecmd); + rc = __de_set_link_ksettings(de, cmd); spin_unlock_irq(&de->lock); return rc; @@ -1690,13 +1701,13 @@ static const struct ethtool_ops de_ethtool_ops = { .get_link = ethtool_op_get_link, .get_drvinfo = de_get_drvinfo, .get_regs_len = de_get_regs_len, - .get_settings = de_get_settings, - .set_settings = de_set_settings, .get_msglevel = de_get_msglevel, .set_msglevel = de_set_msglevel, .get_eeprom = de_get_eeprom, .nway_reset = de_nway_reset, .get_regs = de_get_regs, + .get_link_ksettings = de_get_link_ksettings, + .set_link_ksettings = de_set_link_ksettings, }; static void de21040_get_mac_address(struct de_private *de) diff --git a/drivers/net/ethernet/dec/tulip/uli526x.c b/drivers/net/ethernet/dec/tulip/uli526x.c index f82ebe5d89ee..8d98b259d1ba 100644 --- a/drivers/net/ethernet/dec/tulip/uli526x.c +++ b/drivers/net/ethernet/dec/tulip/uli526x.c @@ -926,48 +926,53 @@ static void uli526x_set_filter_mode(struct net_device * dev) } static void -ULi_ethtool_gset(struct uli526x_board_info *db, struct ethtool_cmd *ecmd) +ULi_ethtool_get_link_ksettings(struct uli526x_board_info *db, + struct ethtool_link_ksettings *cmd) { - ecmd->supported = (SUPPORTED_10baseT_Half | + u32 supported, advertising; + + supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII); - ecmd->advertising = (ADVERTISED_10baseT_Half | + advertising = (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | ADVERTISED_Autoneg | ADVERTISED_MII); + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, + supported); + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising, + advertising); - ecmd->port = PORT_MII; - ecmd->phy_address = db->phy_addr; - - ecmd->transceiver = XCVR_EXTERNAL; + cmd->base.port = PORT_MII; + cmd->base.phy_address = db->phy_addr; - ethtool_cmd_speed_set(ecmd, SPEED_10); - ecmd->duplex = DUPLEX_HALF; + cmd->base.speed = SPEED_10; + cmd->base.duplex = DUPLEX_HALF; if(db->op_mode==ULI526X_100MHF || db->op_mode==ULI526X_100MFD) { - ethtool_cmd_speed_set(ecmd, SPEED_100); + cmd->base.speed = SPEED_100; } if(db->op_mode==ULI526X_10MFD || db->op_mode==ULI526X_100MFD) { - ecmd->duplex = DUPLEX_FULL; + cmd->base.duplex = DUPLEX_FULL; } if(db->link_failed) { - ethtool_cmd_speed_set(ecmd, SPEED_UNKNOWN); - ecmd->duplex = DUPLEX_UNKNOWN; + cmd->base.speed = SPEED_UNKNOWN; + cmd->base.duplex = DUPLEX_UNKNOWN; } if (db->media_mode & ULI526X_AUTO) { - ecmd->autoneg = AUTONEG_ENABLE; + cmd->base.autoneg = AUTONEG_ENABLE; } } @@ -981,10 +986,12 @@ static void netdev_get_drvinfo(struct net_device *dev, strlcpy(info->bus_info, pci_name(np->pdev), sizeof(info->bus_info)); } -static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { +static int netdev_get_link_ksettings(struct net_device *dev, + struct ethtool_link_ksettings *cmd) +{ struct uli526x_board_info *np = netdev_priv(dev); - ULi_ethtool_gset(np, cmd); + ULi_ethtool_get_link_ksettings(np, cmd); return 0; } @@ -1006,9 +1013,9 @@ static void uli526x_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) static const struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, - .get_settings = netdev_get_settings, .get_link = netdev_get_link, .get_wol = uli526x_get_wol, + .get_link_ksettings = netdev_get_link_ksettings, }; /* diff --git a/drivers/net/ethernet/dec/tulip/winbond-840.c b/drivers/net/ethernet/dec/tulip/winbond-840.c index bc9bf88e5831..d1f2f3cc7cfa 100644 --- a/drivers/net/ethernet/dec/tulip/winbond-840.c +++ b/drivers/net/ethernet/dec/tulip/winbond-840.c @@ -1391,25 +1391,27 @@ static void netdev_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo * strlcpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info)); } -static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +static int netdev_get_link_ksettings(struct net_device *dev, + struct ethtool_link_ksettings *cmd) { struct netdev_private *np = netdev_priv(dev); int rc; spin_lock_irq(&np->lock); - rc = mii_ethtool_gset(&np->mii_if, cmd); + rc = mii_ethtool_get_link_ksettings(&np->mii_if, cmd); spin_unlock_irq(&np->lock); return rc; } -static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +static int netdev_set_link_ksettings(struct net_device *dev, + const struct ethtool_link_ksettings *cmd) { struct netdev_private *np = netdev_priv(dev); int rc; spin_lock_irq(&np->lock); - rc = mii_ethtool_sset(&np->mii_if, cmd); + rc = mii_ethtool_set_link_ksettings(&np->mii_if, cmd); spin_unlock_irq(&np->lock); return rc; @@ -1439,12 +1441,12 @@ static void netdev_set_msglevel(struct net_device *dev, u32 value) static const struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, - .get_settings = netdev_get_settings, - .set_settings = netdev_set_settings, .nway_reset = netdev_nway_reset, .get_link = netdev_get_link, .get_msglevel = netdev_get_msglevel, .set_msglevel = netdev_set_msglevel, + .get_link_ksettings = netdev_get_link_ksettings, + .set_link_ksettings = netdev_set_link_ksettings, }; static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) diff --git a/drivers/net/ethernet/dlink/dl2k.c b/drivers/net/ethernet/dlink/dl2k.c index 8c95a8a81e3c..1e350135f11d 100644 --- a/drivers/net/ethernet/dlink/dl2k.c +++ b/drivers/net/ethernet/dlink/dl2k.c @@ -1256,52 +1256,63 @@ static void rio_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info strlcpy(info->bus_info, pci_name(np->pdev), sizeof(info->bus_info)); } -static int rio_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +static int rio_get_link_ksettings(struct net_device *dev, + struct ethtool_link_ksettings *cmd) { struct netdev_private *np = netdev_priv(dev); + u32 supported, advertising; + if (np->phy_media) { /* fiber device */ - cmd->supported = SUPPORTED_Autoneg | SUPPORTED_FIBRE; - cmd->advertising= ADVERTISED_Autoneg | ADVERTISED_FIBRE; - cmd->port = PORT_FIBRE; - cmd->transceiver = XCVR_INTERNAL; + supported = SUPPORTED_Autoneg | SUPPORTED_FIBRE; + advertising = ADVERTISED_Autoneg | ADVERTISED_FIBRE; + cmd->base.port = PORT_FIBRE; } else { /* copper device */ - cmd->supported = SUPPORTED_10baseT_Half | + supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII; - cmd->advertising = ADVERTISED_10baseT_Half | + advertising = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half | - ADVERTISED_100baseT_Full | ADVERTISED_1000baseT_Full| + ADVERTISED_100baseT_Full | ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg | ADVERTISED_MII; - cmd->port = PORT_MII; - cmd->transceiver = XCVR_INTERNAL; + cmd->base.port = PORT_MII; } - if ( np->link_status ) { - ethtool_cmd_speed_set(cmd, np->speed); - cmd->duplex = np->full_duplex ? DUPLEX_FULL : DUPLEX_HALF; + if (np->link_status) { + cmd->base.speed = np->speed; + cmd->base.duplex = np->full_duplex ? DUPLEX_FULL : DUPLEX_HALF; } else { - ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN); - cmd->duplex = DUPLEX_UNKNOWN; + cmd->base.speed = SPEED_UNKNOWN; + cmd->base.duplex = DUPLEX_UNKNOWN; } - if ( np->an_enable) - cmd->autoneg = AUTONEG_ENABLE; + if (np->an_enable) + cmd->base.autoneg = AUTONEG_ENABLE; else - cmd->autoneg = AUTONEG_DISABLE; + cmd->base.autoneg = AUTONEG_DISABLE; + + cmd->base.phy_address = np->phy_addr; + + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, + supported); + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising, + advertising); - cmd->phy_address = np->phy_addr; return 0; } -static int rio_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +static int rio_set_link_ksettings(struct net_device *dev, + const struct ethtool_link_ksettings *cmd) { struct netdev_private *np = netdev_priv(dev); + u32 speed = cmd->base.speed; + u8 duplex = cmd->base.duplex; + netif_carrier_off(dev); - if (cmd->autoneg == AUTONEG_ENABLE) { - if (np->an_enable) + if (cmd->base.autoneg == AUTONEG_ENABLE) { + if (np->an_enable) { return 0; - else { + } else { np->an_enable = 1; mii_set_media(dev); return 0; @@ -1309,18 +1320,18 @@ static int rio_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) } else { np->an_enable = 0; if (np->speed == 1000) { - ethtool_cmd_speed_set(cmd, SPEED_100); - cmd->duplex = DUPLEX_FULL; + speed = SPEED_100; + duplex = DUPLEX_FULL; printk("Warning!! Can't disable Auto negotiation in 1000Mbps, change to Manual 100Mbps, Full duplex.\n"); } - switch (ethtool_cmd_speed(cmd)) { + switch (speed) { case SPEED_10: np->speed = 10; - np->full_duplex = (cmd->duplex == DUPLEX_FULL); + np->full_duplex = (duplex == DUPLEX_FULL); break; case SPEED_100: np->speed = 100; - np->full_duplex = (cmd->duplex == DUPLEX_FULL); + np->full_duplex = (duplex == DUPLEX_FULL); break; case SPEED_1000: /* not supported */ default: @@ -1339,9 +1350,9 @@ static u32 rio_get_link(struct net_device *dev) static const struct ethtool_ops ethtool_ops = { .get_drvinfo = rio_get_drvinfo, - .get_settings = rio_get_settings, - .set_settings = rio_set_settings, .get_link = rio_get_link, + .get_link_ksettings = rio_get_link_ksettings, + .set_link_ksettings = rio_set_link_ksettings, }; static int diff --git a/drivers/net/ethernet/dlink/sundance.c b/drivers/net/ethernet/dlink/sundance.c index 2e5b66762e15..2704bcf023be 100644 --- a/drivers/net/ethernet/dlink/sundance.c +++ b/drivers/net/ethernet/dlink/sundance.c @@ -1664,21 +1664,23 @@ static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) strlcpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info)); } -static int get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) +static int get_link_ksettings(struct net_device *dev, + struct ethtool_link_ksettings *cmd) { struct netdev_private *np = netdev_priv(dev); spin_lock_irq(&np->lock); - mii_ethtool_gset(&np->mii_if, ecmd); + mii_ethtool_get_link_ksettings(&np->mii_if, cmd); spin_unlock_irq(&np->lock); return 0; } -static int set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) +static int set_link_ksettings(struct net_device *dev, + const struct ethtool_link_ksettings *cmd) { struct netdev_private *np = netdev_priv(dev); int res; spin_lock_irq(&np->lock); - res = mii_ethtool_sset(&np->mii_if, ecmd); + res = mii_ethtool_set_link_ksettings(&np->mii_if, cmd); spin_unlock_irq(&np->lock); return res; } @@ -1800,8 +1802,6 @@ static int sundance_set_wol(struct net_device *dev, static const struct ethtool_ops ethtool_ops = { .begin = check_if_running, .get_drvinfo = get_drvinfo, - .get_settings = get_settings, - .set_settings = set_settings, .nway_reset = nway_reset, .get_link = get_link, .get_wol = sundance_get_wol, @@ -1811,6 +1811,8 @@ static const struct ethtool_ops ethtool_ops = { .get_strings = get_strings, .get_sset_count = get_sset_count, .get_ethtool_stats = get_ethtool_stats, + .get_link_ksettings = get_link_ksettings, + .set_link_ksettings = set_link_ksettings, }; static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c index 0a48a31225e6..7d1819c9e8cc 100644 --- a/drivers/net/ethernet/emulex/benet/be_ethtool.c +++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c @@ -606,7 +606,8 @@ bool be_pause_supported(struct be_adapter *adapter) false : true; } -static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) +static int be_get_link_ksettings(struct net_device *netdev, + struct ethtool_link_ksettings *cmd) { struct be_adapter *adapter = netdev_priv(netdev); u8 link_status; @@ -614,13 +615,14 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) int status; u32 auto_speeds; u32 fixed_speeds; + u32 supported = 0, advertising = 0; if (adapter->phy.link_speed < 0) { status = be_cmd_link_status_query(adapter, &link_speed, &link_status, 0); if (!status) be_link_status_update(adapter, link_status); - ethtool_cmd_speed_set(ecmd, link_speed); + cmd->base.speed = link_speed; status = be_cmd_get_phy_info(adapter); if (!status) { @@ -629,58 +631,51 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) be_cmd_query_cable_type(adapter); - ecmd->supported = + supported = convert_to_et_setting(adapter, auto_speeds | fixed_speeds); - ecmd->advertising = + advertising = convert_to_et_setting(adapter, auto_speeds); - ecmd->port = be_get_port_type(adapter); + cmd->base.port = be_get_port_type(adapter); if (adapter->phy.auto_speeds_supported) { - ecmd->supported |= SUPPORTED_Autoneg; - ecmd->autoneg = AUTONEG_ENABLE; - ecmd->advertising |= ADVERTISED_Autoneg; + supported |= SUPPORTED_Autoneg; + cmd->base.autoneg = AUTONEG_ENABLE; + advertising |= ADVERTISED_Autoneg; } - ecmd->supported |= SUPPORTED_Pause; + supported |= SUPPORTED_Pause; if (be_pause_supported(adapter)) - ecmd->advertising |= ADVERTISED_Pause; - - switch (adapter->phy.interface_type) { - case PHY_TYPE_KR_10GB: - case PHY_TYPE_KX4_10GB: - ecmd->transceiver = XCVR_INTERNAL; - break; - default: - ecmd->transceiver = XCVR_EXTERNAL; - break; - } + advertising |= ADVERTISED_Pause; } else { - ecmd->port = PORT_OTHER; - ecmd->autoneg = AUTONEG_DISABLE; - ecmd->transceiver = XCVR_DUMMY1; + cmd->base.port = PORT_OTHER; + cmd->base.autoneg = AUTONEG_DISABLE; } /* Save for future use */ - adapter->phy.link_speed = ethtool_cmd_speed(ecmd); - adapter->phy.port_type = ecmd->port; - adapter->phy.transceiver = ecmd->transceiver; - adapter->phy.autoneg = ecmd->autoneg; - adapter->phy.advertising = ecmd->advertising; - adapter->phy.supported = ecmd->supported; + adapter->phy.link_speed = cmd->base.speed; + adapter->phy.port_type = cmd->base.port; + adapter->phy.autoneg = cmd->base.autoneg; + adapter->phy.advertising = advertising; + adapter->phy.supported = supported; } else { - ethtool_cmd_speed_set(ecmd, adapter->phy.link_speed); - ecmd->port = adapter->phy.port_type; - ecmd->transceiver = adapter->phy.transceiver; - ecmd->autoneg = adapter->phy.autoneg; - ecmd->advertising = adapter->phy.advertising; - ecmd->supported = adapter->phy.supported; + cmd->base.speed = adapter->phy.link_speed; + cmd->base.port = adapter->phy.port_type; + cmd->base.autoneg = adapter->phy.autoneg; + advertising = adapter->phy.advertising; + supported = adapter->phy.supported; } - ecmd->duplex = netif_carrier_ok(netdev) ? DUPLEX_FULL : DUPLEX_UNKNOWN; - ecmd->phy_address = adapter->port_num; + cmd->base.duplex = netif_carrier_ok(netdev) ? + DUPLEX_FULL : DUPLEX_UNKNOWN; + cmd->base.phy_address = adapter->port_num; + + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, + supported); + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising, + advertising); return 0; } @@ -1399,7 +1394,6 @@ static int be_set_priv_flags(struct net_device *netdev, u32 flags) } const struct ethtool_ops be_ethtool_ops = { - .get_settings = be_get_settings, .get_drvinfo = be_get_drvinfo, .get_wol = be_get_wol, .set_wol = be_set_wol, @@ -1433,5 +1427,6 @@ const struct ethtool_ops be_ethtool_ops = { .get_channels = be_get_channels, .set_channels = be_set_channels, .get_module_info = be_get_module_info, - .get_module_eeprom = be_get_module_eeprom + .get_module_eeprom = be_get_module_eeprom, + .get_link_ksettings = be_get_link_ksettings, }; diff --git a/drivers/net/ethernet/faraday/ftmac100.c b/drivers/net/ethernet/faraday/ftmac100.c index dce5f7b7f772..c0ddbbe6c226 100644 --- a/drivers/net/ethernet/faraday/ftmac100.c +++ b/drivers/net/ethernet/faraday/ftmac100.c @@ -825,16 +825,18 @@ static void ftmac100_get_drvinfo(struct net_device *netdev, strlcpy(info->bus_info, dev_name(&netdev->dev), sizeof(info->bus_info)); } -static int ftmac100_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd) +static int ftmac100_get_link_ksettings(struct net_device *netdev, + struct ethtool_link_ksettings *cmd) { struct ftmac100 *priv = netdev_priv(netdev); - return mii_ethtool_gset(&priv->mii, cmd); + return mii_ethtool_get_link_ksettings(&priv->mii, cmd); } -static int ftmac100_set_settings(struct net_device *netdev, struct ethtool_cmd *cmd) +static int ftmac100_set_link_ksettings(struct net_device *netdev, + const struct ethtool_link_ksettings *cmd) { struct ftmac100 *priv = netdev_priv(netdev); - return mii_ethtool_sset(&priv->mii, cmd); + return mii_ethtool_set_link_ksettings(&priv->mii, cmd); } static int ftmac100_nway_reset(struct net_device *netdev) @@ -850,11 +852,11 @@ static u32 ftmac100_get_link(struct net_device *netdev) } static const struct ethtool_ops ftmac100_ethtool_ops = { - .set_settings = ftmac100_set_settings, - .get_settings = ftmac100_get_settings, .get_drvinfo = ftmac100_get_drvinfo, .nway_reset = ftmac100_nway_reset, .get_link = ftmac100_get_link, + .get_link_ksettings = ftmac100_get_link_ksettings, + .set_link_ksettings = ftmac100_set_link_ksettings, }; /****************************************************************************** diff --git a/drivers/net/ethernet/fealnx.c b/drivers/net/ethernet/fealnx.c index 9cb436cb3745..766636a7c25e 100644 --- a/drivers/net/ethernet/fealnx.c +++ b/drivers/net/ethernet/fealnx.c @@ -1817,25 +1817,27 @@ static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *i strlcpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info)); } -static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +static int netdev_get_link_ksettings(struct net_device *dev, + struct ethtool_link_ksettings *cmd) { struct netdev_private *np = netdev_priv(dev); int rc; spin_lock_irq(&np->lock); - rc = mii_ethtool_gset(&np->mii, cmd); + rc = mii_ethtool_get_link_ksettings(&np->mii, cmd); spin_unlock_irq(&np->lock); return rc; } -static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +static int netdev_set_link_ksettings(struct net_device *dev, + const struct ethtool_link_ksettings *cmd) { struct netdev_private *np = netdev_priv(dev); int rc; spin_lock_irq(&np->lock); - rc = mii_ethtool_sset(&np->mii, cmd); + rc = mii_ethtool_set_link_ksettings(&np->mii, cmd); spin_unlock_irq(&np->lock); return rc; @@ -1865,12 +1867,12 @@ static void netdev_set_msglevel(struct net_device *dev, u32 value) static const struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, - .get_settings = netdev_get_settings, - .set_settings = netdev_set_settings, .nway_reset = netdev_nway_reset, .get_link = netdev_get_link, .get_msglevel = netdev_get_msglevel, .set_msglevel = netdev_set_msglevel, + .get_link_ksettings = netdev_get_link_ksettings, + .set_link_ksettings = netdev_set_link_ksettings, }; static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) diff --git a/drivers/net/ethernet/sfc/falcon/efx.c b/drivers/net/ethernet/sfc/falcon/efx.c index 5c5cb3c4c12e..438ef9e7a10d 100644 --- a/drivers/net/ethernet/sfc/falcon/efx.c +++ b/drivers/net/ethernet/sfc/falcon/efx.c @@ -986,7 +986,7 @@ void ef4_mac_reconfigure(struct ef4_nic *efx) /* Push loopback/power/transmit disable settings to the PHY, and reconfigure * the MAC appropriately. All other PHY configuration changes are pushed - * through phy_op->set_settings(), and pushed asynchronously to the MAC + * through phy_op->set_link_ksettings(), and pushed asynchronously to the MAC * through ef4_monitor(). * * Callers must hold the mac_lock diff --git a/drivers/net/ethernet/sfc/falcon/ethtool.c b/drivers/net/ethernet/sfc/falcon/ethtool.c index 8e1929b01a32..56049157a5af 100644 --- a/drivers/net/ethernet/sfc/falcon/ethtool.c +++ b/drivers/net/ethernet/sfc/falcon/ethtool.c @@ -115,44 +115,47 @@ static int ef4_ethtool_phys_id(struct net_device *net_dev, } /* This must be called with rtnl_lock held. */ -static int ef4_ethtool_get_settings(struct net_device *net_dev, - struct ethtool_cmd *ecmd) +static int +ef4_ethtool_get_link_ksettings(struct net_device *net_dev, + struct ethtool_link_ksettings *cmd) { struct ef4_nic *efx = netdev_priv(net_dev); struct ef4_link_state *link_state = &efx->link_state; mutex_lock(&efx->mac_lock); - efx->phy_op->get_settings(efx, ecmd); + efx->phy_op->get_link_ksettings(efx, cmd); mutex_unlock(&efx->mac_lock); /* Both MACs support pause frames (bidirectional and respond-only) */ - ecmd->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; + ethtool_link_ksettings_add_link_mode(cmd, supported, Pause); + ethtool_link_ksettings_add_link_mode(cmd, supported, Asym_Pause); if (LOOPBACK_INTERNAL(efx)) { - ethtool_cmd_speed_set(ecmd, link_state->speed); - ecmd->duplex = link_state->fd ? DUPLEX_FULL : DUPLEX_HALF; + cmd->base.speed = link_state->speed; + cmd->base.duplex = link_state->fd ? DUPLEX_FULL : DUPLEX_HALF; } return 0; } /* This must be called with rtnl_lock held. */ -static int ef4_ethtool_set_settings(struct net_device *net_dev, - struct ethtool_cmd *ecmd) +static int +ef4_ethtool_set_link_ksettings(struct net_device *net_dev, + const struct ethtool_link_ksettings *cmd) { struct ef4_nic *efx = netdev_priv(net_dev); int rc; /* GMAC does not support 1000Mbps HD */ - if ((ethtool_cmd_speed(ecmd) == SPEED_1000) && - (ecmd->duplex != DUPLEX_FULL)) { + if ((cmd->base.speed == SPEED_1000) && + (cmd->base.duplex != DUPLEX_FULL)) { netif_dbg(efx, drv, efx->net_dev, "rejecting unsupported 1000Mbps HD setting\n"); return -EINVAL; } mutex_lock(&efx->mac_lock); - rc = efx->phy_op->set_settings(efx, ecmd); + rc = efx->phy_op->set_link_ksettings(efx, cmd); mutex_unlock(&efx->mac_lock); return rc; } @@ -1310,8 +1313,6 @@ static int ef4_ethtool_get_module_info(struct net_device *net_dev, } const struct ethtool_ops ef4_ethtool_ops = { - .get_settings = ef4_ethtool_get_settings, - .set_settings = ef4_ethtool_set_settings, .get_drvinfo = ef4_ethtool_get_drvinfo, .get_regs_len = ef4_ethtool_get_regs_len, .get_regs = ef4_ethtool_get_regs, @@ -1340,4 +1341,6 @@ const struct ethtool_ops ef4_ethtool_ops = { .set_rxfh = ef4_ethtool_set_rxfh, .get_module_info = ef4_ethtool_get_module_info, .get_module_eeprom = ef4_ethtool_get_module_eeprom, + .get_link_ksettings = ef4_ethtool_get_link_ksettings, + .set_link_ksettings = ef4_ethtool_set_link_ksettings, }; diff --git a/drivers/net/ethernet/sfc/falcon/mdio_10g.c b/drivers/net/ethernet/sfc/falcon/mdio_10g.c index e7d7c09296aa..ee0713f03d01 100644 --- a/drivers/net/ethernet/sfc/falcon/mdio_10g.c +++ b/drivers/net/ethernet/sfc/falcon/mdio_10g.c @@ -226,33 +226,45 @@ void ef4_mdio_set_mmds_lpower(struct ef4_nic *efx, } /** - * ef4_mdio_set_settings - Set (some of) the PHY settings over MDIO. + * ef4_mdio_set_link_ksettings - Set (some of) the PHY settings over MDIO. * @efx: Efx NIC - * @ecmd: New settings + * @cmd: New settings */ -int ef4_mdio_set_settings(struct ef4_nic *efx, struct ethtool_cmd *ecmd) +int ef4_mdio_set_link_ksettings(struct ef4_nic *efx, + const struct ethtool_link_ksettings *cmd) { - struct ethtool_cmd prev = { .cmd = ETHTOOL_GSET }; - - efx->phy_op->get_settings(efx, &prev); - - if (ecmd->advertising == prev.advertising && - ethtool_cmd_speed(ecmd) == ethtool_cmd_speed(&prev) && - ecmd->duplex == prev.duplex && - ecmd->port == prev.port && - ecmd->autoneg == prev.autoneg) + struct ethtool_link_ksettings prev = { + .base.cmd = ETHTOOL_GLINKSETTINGS + }; + u32 prev_advertising, advertising; + u32 prev_supported; + + efx->phy_op->get_link_ksettings(efx, &prev); + + ethtool_convert_link_mode_to_legacy_u32(&advertising, + cmd->link_modes.advertising); + ethtool_convert_link_mode_to_legacy_u32(&prev_advertising, + prev.link_modes.advertising); + ethtool_convert_link_mode_to_legacy_u32(&prev_supported, + prev.link_modes.supported); + + if (advertising == prev_advertising && + cmd->base.speed == prev.base.speed && + cmd->base.duplex == prev.base.duplex && + cmd->base.port == prev.base.port && + cmd->base.autoneg == prev.base.autoneg) return 0; /* We can only change these settings for -T PHYs */ - if (prev.port != PORT_TP || ecmd->port != PORT_TP) + if (prev.base.port != PORT_TP || cmd->base.port != PORT_TP) return -EINVAL; /* Check that PHY supports these settings */ - if (!ecmd->autoneg || - (ecmd->advertising | SUPPORTED_Autoneg) & ~prev.supported) + if (!cmd->base.autoneg || + (advertising | SUPPORTED_Autoneg) & ~prev_supported) return -EINVAL; - ef4_link_set_advertising(efx, ecmd->advertising | ADVERTISED_Autoneg); + ef4_link_set_advertising(efx, advertising | ADVERTISED_Autoneg); ef4_mdio_an_reconfigure(efx); return 0; } diff --git a/drivers/net/ethernet/sfc/falcon/mdio_10g.h b/drivers/net/ethernet/sfc/falcon/mdio_10g.h index 885cf7a834a6..53cb5cc4ad37 100644 --- a/drivers/net/ethernet/sfc/falcon/mdio_10g.h +++ b/drivers/net/ethernet/sfc/falcon/mdio_10g.h @@ -83,7 +83,8 @@ void ef4_mdio_set_mmds_lpower(struct ef4_nic *efx, int low_power, unsigned int mmd_mask); /* Set (some of) the PHY settings over MDIO */ -int ef4_mdio_set_settings(struct ef4_nic *efx, struct ethtool_cmd *ecmd); +int ef4_mdio_set_link_ksettings(struct ef4_nic *efx, + const struct ethtool_link_ksettings *cmd); /* Push advertising flags and restart autonegotiation */ void ef4_mdio_an_reconfigure(struct ef4_nic *efx); diff --git a/drivers/net/ethernet/sfc/falcon/net_driver.h b/drivers/net/ethernet/sfc/falcon/net_driver.h index 210b28f7d2a1..fe59dd67f918 100644 --- a/drivers/net/ethernet/sfc/falcon/net_driver.h +++ b/drivers/net/ethernet/sfc/falcon/net_driver.h @@ -684,8 +684,8 @@ static inline bool ef4_link_state_equal(const struct ef4_link_state *left, * @reconfigure: Reconfigure PHY (e.g. for new link parameters) * @poll: Update @link_state and report whether it changed. * Serialised by the mac_lock. - * @get_settings: Get ethtool settings. Serialised by the mac_lock. - * @set_settings: Set ethtool settings. Serialised by the mac_lock. + * @get_link_ksettings: Get ethtool settings. Serialised by the mac_lock. + * @set_link_ksettings: Set ethtool settings. Serialised by the mac_lock. * @set_npage_adv: Set abilities advertised in (Extended) Next Page * (only needed where AN bit is set in mmds) * @test_alive: Test that PHY is 'alive' (online) @@ -700,10 +700,10 @@ struct ef4_phy_operations { void (*remove) (struct ef4_nic *efx); int (*reconfigure) (struct ef4_nic *efx); bool (*poll) (struct ef4_nic *efx); - void (*get_settings) (struct ef4_nic *efx, - struct ethtool_cmd *ecmd); - int (*set_settings) (struct ef4_nic *efx, - struct ethtool_cmd *ecmd); + void (*get_link_ksettings)(struct ef4_nic *efx, + struct ethtool_link_ksettings *cmd); + int (*set_link_ksettings)(struct ef4_nic *efx, + const struct ethtool_link_ksettings *cmd); void (*set_npage_adv) (struct ef4_nic *efx, u32); int (*test_alive) (struct ef4_nic *efx); const char *(*test_name) (struct ef4_nic *efx, unsigned int index); diff --git a/drivers/net/ethernet/sfc/falcon/qt202x_phy.c b/drivers/net/ethernet/sfc/falcon/qt202x_phy.c index d29331652548..f5e0f18d4ea8 100644 --- a/drivers/net/ethernet/sfc/falcon/qt202x_phy.c +++ b/drivers/net/ethernet/sfc/falcon/qt202x_phy.c @@ -437,9 +437,10 @@ static int qt202x_phy_reconfigure(struct ef4_nic *efx) return 0; } -static void qt202x_phy_get_settings(struct ef4_nic *efx, struct ethtool_cmd *ecmd) +static void qt202x_phy_get_link_ksettings(struct ef4_nic *efx, + struct ethtool_link_ksettings *cmd) { - mdio45_ethtool_gset(&efx->mdio, ecmd); + mdio45_ethtool_ksettings_get(&efx->mdio, cmd); } static void qt202x_phy_remove(struct ef4_nic *efx) @@ -487,8 +488,8 @@ const struct ef4_phy_operations falcon_qt202x_phy_ops = { .poll = qt202x_phy_poll, .fini = ef4_port_dummy_op_void, .remove = qt202x_phy_remove, - .get_settings = qt202x_phy_get_settings, - .set_settings = ef4_mdio_set_settings, + .get_link_ksettings = qt202x_phy_get_link_ksettings, + .set_link_ksettings = ef4_mdio_set_link_ksettings, .test_alive = ef4_mdio_test_alive, .get_module_eeprom = qt202x_phy_get_module_eeprom, .get_module_info = qt202x_phy_get_module_info, diff --git a/drivers/net/ethernet/sfc/falcon/tenxpress.c b/drivers/net/ethernet/sfc/falcon/tenxpress.c index acc548a1c4d6..ff9b4e2b590c 100644 --- a/drivers/net/ethernet/sfc/falcon/tenxpress.c +++ b/drivers/net/ethernet/sfc/falcon/tenxpress.c @@ -351,9 +351,6 @@ static int tenxpress_phy_reconfigure(struct ef4_nic *efx) return 0; } -static void -tenxpress_get_settings(struct ef4_nic *efx, struct ethtool_cmd *ecmd); - /* Poll for link state changes */ static bool tenxpress_phy_poll(struct ef4_nic *efx) { @@ -443,7 +440,8 @@ sfx7101_run_tests(struct ef4_nic *efx, int *results, unsigned flags) } static void -tenxpress_get_settings(struct ef4_nic *efx, struct ethtool_cmd *ecmd) +tenxpress_get_link_ksettings(struct ef4_nic *efx, + struct ethtool_link_ksettings *cmd) { u32 adv = 0, lpa = 0; int reg; @@ -455,20 +453,22 @@ tenxpress_get_settings(struct ef4_nic *efx, struct ethtool_cmd *ecmd) if (reg & MDIO_AN_10GBT_STAT_LP10G) lpa |= ADVERTISED_10000baseT_Full; - mdio45_ethtool_gset_npage(&efx->mdio, ecmd, adv, lpa); + mdio45_ethtool_ksettings_get_npage(&efx->mdio, cmd, adv, lpa); /* In loopback, the PHY automatically brings up the correct interface, * but doesn't advertise the correct speed. So override it */ if (LOOPBACK_EXTERNAL(efx)) - ethtool_cmd_speed_set(ecmd, SPEED_10000); + cmd->base.speed = SPEED_10000; } -static int tenxpress_set_settings(struct ef4_nic *efx, struct ethtool_cmd *ecmd) +static int +tenxpress_set_link_ksettings(struct ef4_nic *efx, + const struct ethtool_link_ksettings *cmd) { - if (!ecmd->autoneg) + if (!cmd->base.autoneg) return -EINVAL; - return ef4_mdio_set_settings(efx, ecmd); + return ef4_mdio_set_link_ksettings(efx, cmd); } static void sfx7101_set_npage_adv(struct ef4_nic *efx, u32 advertising) @@ -485,8 +485,8 @@ const struct ef4_phy_operations falcon_sfx7101_phy_ops = { .poll = tenxpress_phy_poll, .fini = sfx7101_phy_fini, .remove = tenxpress_phy_remove, - .get_settings = tenxpress_get_settings, - .set_settings = tenxpress_set_settings, + .get_link_ksettings = tenxpress_get_link_ksettings, + .set_link_ksettings = tenxpress_set_link_ksettings, .set_npage_adv = sfx7101_set_npage_adv, .test_alive = ef4_mdio_test_alive, .test_name = sfx7101_test_name, diff --git a/drivers/net/ethernet/sfc/falcon/txc43128_phy.c b/drivers/net/ethernet/sfc/falcon/txc43128_phy.c index 18421f5e880f..3c55fd23c271 100644 --- a/drivers/net/ethernet/sfc/falcon/txc43128_phy.c +++ b/drivers/net/ethernet/sfc/falcon/txc43128_phy.c @@ -540,9 +540,10 @@ static int txc43128_run_tests(struct ef4_nic *efx, int *results, unsigned flags) return rc; } -static void txc43128_get_settings(struct ef4_nic *efx, struct ethtool_cmd *ecmd) +static void txc43128_get_link_ksettings(struct ef4_nic *efx, + struct ethtool_link_ksettings *cmd) { - mdio45_ethtool_gset(&efx->mdio, ecmd); + mdio45_ethtool_ksettings_get(&efx->mdio, cmd); } const struct ef4_phy_operations falcon_txc_phy_ops = { @@ -552,8 +553,8 @@ const struct ef4_phy_operations falcon_txc_phy_ops = { .poll = txc43128_phy_poll, .fini = txc43128_phy_fini, .remove = txc43128_phy_remove, - .get_settings = txc43128_get_settings, - .set_settings = ef4_mdio_set_settings, + .get_link_ksettings = txc43128_get_link_ksettings, + .set_link_ksettings = ef4_mdio_set_link_ksettings, .test_alive = ef4_mdio_test_alive, .run_tests = txc43128_run_tests, .test_name = txc43128_test_name, diff --git a/drivers/net/mdio.c b/drivers/net/mdio.c index 3e027ed0b3bb..077364cbf439 100644 --- a/drivers/net/mdio.c +++ b/drivers/net/mdio.c @@ -342,6 +342,184 @@ void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio, EXPORT_SYMBOL(mdio45_ethtool_gset_npage); /** + * mdio45_ethtool_ksettings_get_npage - get settings for ETHTOOL_GLINKSETTINGS + * @mdio: MDIO interface + * @cmd: Ethtool request structure + * @npage_adv: Modes currently advertised on next pages + * @npage_lpa: Modes advertised by link partner on next pages + * + * The @cmd parameter is expected to have been cleared before calling + * mdio45_ethtool_ksettings_get_npage(). + * + * Since the CSRs for auto-negotiation using next pages are not fully + * standardised, this function does not attempt to decode them. The + * caller must pass them in. + */ +void mdio45_ethtool_ksettings_get_npage(const struct mdio_if_info *mdio, + struct ethtool_link_ksettings *cmd, + u32 npage_adv, u32 npage_lpa) +{ + int reg; + u32 speed, supported = 0, advertising = 0, lp_advertising = 0; + + BUILD_BUG_ON(MDIO_SUPPORTS_C22 != ETH_MDIO_SUPPORTS_C22); + BUILD_BUG_ON(MDIO_SUPPORTS_C45 != ETH_MDIO_SUPPORTS_C45); + + cmd->base.phy_address = mdio->prtad; + cmd->base.mdio_support = + mdio->mode_support & (MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22); + + reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, + MDIO_CTRL2); + switch (reg & MDIO_PMA_CTRL2_TYPE) { + case MDIO_PMA_CTRL2_10GBT: + case MDIO_PMA_CTRL2_1000BT: + case MDIO_PMA_CTRL2_100BTX: + case MDIO_PMA_CTRL2_10BT: + cmd->base.port = PORT_TP; + supported = SUPPORTED_TP; + reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, + MDIO_SPEED); + if (reg & MDIO_SPEED_10G) + supported |= SUPPORTED_10000baseT_Full; + if (reg & MDIO_PMA_SPEED_1000) + supported |= (SUPPORTED_1000baseT_Full | + SUPPORTED_1000baseT_Half); + if (reg & MDIO_PMA_SPEED_100) + supported |= (SUPPORTED_100baseT_Full | + SUPPORTED_100baseT_Half); + if (reg & MDIO_PMA_SPEED_10) + supported |= (SUPPORTED_10baseT_Full | + SUPPORTED_10baseT_Half); + advertising = ADVERTISED_TP; + break; + + case MDIO_PMA_CTRL2_10GBCX4: + cmd->base.port = PORT_OTHER; + supported = 0; + advertising = 0; + break; + + case MDIO_PMA_CTRL2_10GBKX4: + case MDIO_PMA_CTRL2_10GBKR: + case MDIO_PMA_CTRL2_1000BKX: + cmd->base.port = PORT_OTHER; + supported = SUPPORTED_Backplane; + reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, + MDIO_PMA_EXTABLE); + if (reg & MDIO_PMA_EXTABLE_10GBKX4) + supported |= SUPPORTED_10000baseKX4_Full; + if (reg & MDIO_PMA_EXTABLE_10GBKR) + supported |= SUPPORTED_10000baseKR_Full; + if (reg & MDIO_PMA_EXTABLE_1000BKX) + supported |= SUPPORTED_1000baseKX_Full; + reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, + MDIO_PMA_10GBR_FECABLE); + if (reg & MDIO_PMA_10GBR_FECABLE_ABLE) + supported |= SUPPORTED_10000baseR_FEC; + advertising = ADVERTISED_Backplane; + break; + + /* All the other defined modes are flavours of optical */ + default: + cmd->base.port = PORT_FIBRE; + supported = SUPPORTED_FIBRE; + advertising = ADVERTISED_FIBRE; + break; + } + + if (mdio->mmds & MDIO_DEVS_AN) { + supported |= SUPPORTED_Autoneg; + reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_AN, + MDIO_CTRL1); + if (reg & MDIO_AN_CTRL1_ENABLE) { + cmd->base.autoneg = AUTONEG_ENABLE; + advertising |= + ADVERTISED_Autoneg | + mdio45_get_an(mdio, MDIO_AN_ADVERTISE) | + npage_adv; + } else { + cmd->base.autoneg = AUTONEG_DISABLE; + } + } else { + cmd->base.autoneg = AUTONEG_DISABLE; + } + + if (cmd->base.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 (an_stat & MDIO_AN_STAT1_COMPLETE) { + lp_advertising = + mdio45_get_an(mdio, MDIO_AN_LPA) | npage_lpa; + if (an_stat & MDIO_AN_STAT1_LPABLE) + lp_advertising |= ADVERTISED_Autoneg; + modes = advertising & lp_advertising; + } + if ((modes & ~ADVERTISED_Autoneg) == 0) + modes = advertising; + + if (modes & (ADVERTISED_10000baseT_Full | + ADVERTISED_10000baseKX4_Full | + ADVERTISED_10000baseKR_Full)) { + speed = SPEED_10000; + cmd->base.duplex = DUPLEX_FULL; + } else if (modes & (ADVERTISED_1000baseT_Full | + ADVERTISED_1000baseT_Half | + ADVERTISED_1000baseKX_Full)) { + speed = SPEED_1000; + cmd->base.duplex = !(modes & ADVERTISED_1000baseT_Half); + } else if (modes & (ADVERTISED_100baseT_Full | + ADVERTISED_100baseT_Half)) { + speed = SPEED_100; + cmd->base.duplex = !!(modes & ADVERTISED_100baseT_Full); + } else { + speed = SPEED_10; + cmd->base.duplex = !!(modes & ADVERTISED_10baseT_Full); + } + } else { + /* Report forced settings */ + reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, + MDIO_CTRL1); + speed = (((reg & MDIO_PMA_CTRL1_SPEED1000) ? 100 : 1) + * ((reg & MDIO_PMA_CTRL1_SPEED100) ? 100 : 10)); + cmd->base.duplex = (reg & MDIO_CTRL1_FULLDPLX || + speed == SPEED_10000); + } + + cmd->base.speed = speed; + + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, + supported); + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising, + advertising); + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.lp_advertising, + lp_advertising); + + /* 10GBASE-T MDI/MDI-X */ + if (cmd->base.port == PORT_TP && (cmd->base.speed == SPEED_10000)) { + switch (mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, + MDIO_PMA_10GBT_SWAPPOL)) { + case MDIO_PMA_10GBT_SWAPPOL_ABNX | MDIO_PMA_10GBT_SWAPPOL_CDNX: + cmd->base.eth_tp_mdix = ETH_TP_MDI; + break; + case 0: + cmd->base.eth_tp_mdix = ETH_TP_MDI_X; + break; + default: + /* It's complicated... */ + cmd->base.eth_tp_mdix = ETH_TP_MDI_INVALID; + break; + } + } +} +EXPORT_SYMBOL(mdio45_ethtool_ksettings_get_npage); + +/** * mdio_mii_ioctl - MII ioctl interface for MDIO (clause 22 or 45) PHYs * @mdio: MDIO interface * @mii_data: MII ioctl data structure diff --git a/include/linux/mdio.h b/include/linux/mdio.h index bf9d1d750693..b6587a4b32e7 100644 --- a/include/linux/mdio.h +++ b/include/linux/mdio.h @@ -130,6 +130,10 @@ extern int mdio45_nway_restart(const struct mdio_if_info *mdio); extern void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio, struct ethtool_cmd *ecmd, u32 npage_adv, u32 npage_lpa); +extern void +mdio45_ethtool_ksettings_get_npage(const struct mdio_if_info *mdio, + struct ethtool_link_ksettings *cmd, + u32 npage_adv, u32 npage_lpa); /** * mdio45_ethtool_gset - get settings for ETHTOOL_GSET @@ -147,6 +151,23 @@ static inline void mdio45_ethtool_gset(const struct mdio_if_info *mdio, mdio45_ethtool_gset_npage(mdio, ecmd, 0, 0); } +/** + * mdio45_ethtool_ksettings_get - get settings for ETHTOOL_GLINKSETTINGS + * @mdio: MDIO interface + * @cmd: Ethtool request structure + * + * Since the CSRs for auto-negotiation using next pages are not fully + * standardised, this function does not attempt to decode them. Use + * mdio45_ethtool_ksettings_get_npage() to specify advertisement bits + * from next pages. + */ +static inline void +mdio45_ethtool_ksettings_get(const struct mdio_if_info *mdio, + struct ethtool_link_ksettings *cmd) +{ + mdio45_ethtool_ksettings_get_npage(mdio, cmd, 0, 0); +} + extern int mdio_mii_ioctl(const struct mdio_if_info *mdio, struct mii_ioctl_data *mii_data, int cmd); |