|
@@ -341,6 +341,184 @@ void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio,
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(mdio45_ethtool_gset_npage);
|
|
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_mii_ioctl - MII ioctl interface for MDIO (clause 22 or 45) PHYs
|
|
* @mdio: MDIO interface
|
|
* @mdio: MDIO interface
|