/****************************************************************************** * mv_eth_tool_nway_reset * Description: * ethtool restart auto negotiation * INPUT: * netdev Network device structure pointer * OUTPUT * None * RETURN: * 0 on success * *******************************************************************************/ int mv_eth_tool_nway_reset(struct net_device *netdev) { mv_eth_priv *priv = MV_ETH_PRIV(netdev); MV_U32 mv_phy_addr = (MV_U32)(priv->phy_id); if (mvEthPhyRestartAN(mv_phy_addr, MV_ETH_TOOL_AN_TIMEOUT) != MV_OK) return -EINVAL; return 0; }
/****************************************************************************** * mv_eth_tool_nway_reset * Description: * ethtool restart auto negotiation * INPUT: * netdev Network device structure pointer * OUTPUT * None * RETURN: * 0 on success * *******************************************************************************/ int mv_eth_tool_nway_reset(struct net_device *netdev) { struct eth_port *priv = MV_ETH_PRIV(netdev); MV_U32 mv_phy_addr = mvBoardPhyAddrGet(priv->port); #ifdef CONFIG_MV_ETH_SWITCH if (isSwitch(priv)) return -EPERM; #endif /* CONFIG_MV_ETH_SWITCH */ if (mvEthPhyRestartAN(mv_phy_addr, MV_ETH_TOOL_AN_TIMEOUT) != MV_OK) return -EINVAL; return 0; }
/****************************************************************************** * mv_eth_tool_nway_reset * Description: * ethtool restart auto negotiation * INPUT: * netdev Network device structure pointer * OUTPUT * None * RETURN: * 0 on success * *******************************************************************************/ int mv_eth_tool_nway_reset(struct net_device *netdev) { struct eth_port *priv = MV_ETH_PRIV(netdev); MV_U32 phy_addr; if ((priv == NULL) || (isSwitch(priv)) || (MV_PON_PORT(priv->port))) { printk(KERN_ERR "interface %s is not supported\n", netdev->name); return -EOPNOTSUPP; } phy_addr = mvBoardPhyAddrGet(priv->port); if (mvEthPhyRestartAN(phy_addr, MV_ETH_TOOL_AN_TIMEOUT) != MV_OK) return -EINVAL; return 0; }
/****************************************************************************** * mv_eth_tool_set_pauseparam * Description: * ethtool configure pause parameters * INPUT: * netdev Network device structure pointer * pause Pause paranmeters * OUTPUT * None * RETURN: * 0 on success * *******************************************************************************/ int mv_eth_tool_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) { struct eth_port *priv = MV_ETH_PRIV(netdev); int port = priv->port; MV_U32 phy_addr; MV_STATUS status = MV_FAIL; #ifdef CONFIG_MV_ETH_SWITCH if (isSwitch(priv)) return -EPERM; #endif /* CONFIG_MV_ETH_SWITCH */ if (pause->rx_pause && pause->tx_pause) { /* Enable FC */ if (pause->autoneg) { /* autoneg enable */ status = mvNetaFlowCtrlSet(port, MV_ETH_FC_AN_SYM); } else { /* autoneg disable */ status = mvNetaFlowCtrlSet(port, MV_ETH_FC_ENABLE); } } else if (!pause->rx_pause && !pause->tx_pause) { /* Disable FC */ if (pause->autoneg) { /* autoneg enable */ status = mvNetaFlowCtrlSet(port, MV_ETH_FC_AN_NO); } else { /* autoneg disable */ status = mvNetaFlowCtrlSet(port, MV_ETH_FC_DISABLE); } } /* Only symmetric change for RX and TX flow control is allowed */ if (status == MV_OK) { phy_addr = mvBoardPhyAddrGet(priv->port); status = mvEthPhyRestartAN(phy_addr, MV_ETH_TOOL_AN_TIMEOUT); } if (status != MV_OK) return -EINVAL; return 0; }
/****************************************************************************** * mv_eth_tool_set_pauseparam * Description: * ethtool configure pause parameters * INPUT: * netdev Network device structure pointer * pause Pause paranmeters * OUTPUT * None * RETURN: * 0 on success * *******************************************************************************/ int mv_eth_tool_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) { struct eth_port *priv = MV_ETH_PRIV(netdev); int port = priv->port; MV_U32 phy_addr; MV_STATUS status = MV_FAIL; if ((priv == NULL) || (isSwitch(priv)) || (MV_PON_PORT(priv->port))) { printk(KERN_ERR "%s is not supported on %s\n", __func__, netdev->name); return -EOPNOTSUPP; } if (pause->rx_pause && pause->tx_pause) { /* Enable FC */ if (pause->autoneg) { /* autoneg enable */ status = mvNetaFlowCtrlSet(port, MV_ETH_FC_AN_SYM); } else { /* autoneg disable */ status = mvNetaFlowCtrlSet(port, MV_ETH_FC_ENABLE); } } else if (!pause->rx_pause && !pause->tx_pause) { /* Disable FC */ if (pause->autoneg) { /* autoneg enable */ status = mvNetaFlowCtrlSet(port, MV_ETH_FC_AN_NO); } else { /* autoneg disable */ status = mvNetaFlowCtrlSet(port, MV_ETH_FC_DISABLE); } } /* Only symmetric change for RX and TX flow control is allowed */ if (status == MV_OK) { phy_addr = mvBoardPhyAddrGet(priv->port); status = mvEthPhyRestartAN(phy_addr, MV_ETH_TOOL_AN_TIMEOUT); } if (status != MV_OK) return -EINVAL; return 0; }
/****************************************************************************** * mv_eth_tool_restore_settings * Description: * restore saved speed/dublex/an settings * INPUT: * netdev Network device structure pointer * OUTPUT * None * RETURN: * 0 for success * *******************************************************************************/ int mv_eth_tool_restore_settings(struct net_device *netdev) { struct eth_port *priv = MV_ETH_PRIV(netdev); int mv_phy_speed, mv_phy_duplex; MV_U32 mv_phy_addr = mvBoardPhyAddrGet(priv->port); MV_ETH_PORT_SPEED mv_mac_speed; MV_ETH_PORT_DUPLEX mv_mac_duplex; int err = -EINVAL; if ((priv == NULL) || (isSwitch(priv))) return -EOPNOTSUPP; switch (priv->speed_cfg) { case SPEED_10: mv_phy_speed = 0; mv_mac_speed = MV_ETH_SPEED_10; break; case SPEED_100: mv_phy_speed = 1; mv_mac_speed = MV_ETH_SPEED_100; break; case SPEED_1000: mv_phy_speed = 2; mv_mac_speed = MV_ETH_SPEED_1000; break; default: return -EINVAL; } switch (priv->duplex_cfg) { case DUPLEX_HALF: mv_phy_duplex = 0; mv_mac_duplex = MV_ETH_DUPLEX_HALF; break; case DUPLEX_FULL: mv_phy_duplex = 1; mv_mac_duplex = MV_ETH_DUPLEX_FULL; break; default: return -EINVAL; } if (priv->autoneg_cfg == AUTONEG_ENABLE) { err = mvNetaSpeedDuplexSet(priv->port, MV_ETH_SPEED_AN, MV_ETH_DUPLEX_AN); if (!err) err = mvEthPhyAdvertiseSet(mv_phy_addr, priv->advertise_cfg); /* Restart AN on PHY enables it */ if (!err) { err = mvEthPhyRestartAN(mv_phy_addr, MV_ETH_TOOL_AN_TIMEOUT); if (err == MV_TIMEOUT) { MV_ETH_PORT_STATUS ps; mvNetaLinkStatus(priv->port, &ps); if (!ps.linkup) err = 0; } } } else if (priv->autoneg_cfg == AUTONEG_DISABLE) { err = mvEthPhyDisableAN(mv_phy_addr, mv_phy_speed, mv_phy_duplex); if (!err) err = mvNetaSpeedDuplexSet(priv->port, mv_mac_speed, mv_mac_duplex); } else { err = -EINVAL; } return err; }
/****************************************************************************** * mv_eth_tool_restore_settings * Description: * restore saved speed/dublex/an settings * INPUT: * netdev Network device structure pointer * OUTPUT * None * RETURN: * 0 for success * *******************************************************************************/ int mv_eth_tool_restore_settings(struct net_device *netdev) { mv_eth_priv *priv = MV_ETH_PRIV(netdev); int mv_phy_speed, mv_phy_duplex; MV_U32 mv_phy_addr = priv->phy_id; MV_ETH_PORT_SPEED mv_mac_speed; MV_ETH_PORT_DUPLEX mv_mac_duplex; int err = -EINVAL; switch (priv->speed_cfg) { case SPEED_10: mv_phy_speed = 0; mv_mac_speed = MV_ETH_SPEED_10; break; case SPEED_100: mv_phy_speed = 1; mv_mac_speed = MV_ETH_SPEED_100; break; case SPEED_1000: mv_phy_speed = 2; mv_mac_speed = MV_ETH_SPEED_1000; break; default: return -EINVAL; } switch (priv->duplex_cfg) { case DUPLEX_HALF: mv_phy_duplex = 0; mv_mac_duplex = MV_ETH_DUPLEX_HALF; break; case DUPLEX_FULL: mv_phy_duplex = 1; mv_mac_duplex = MV_ETH_DUPLEX_FULL; break; default: return -EINVAL; } if (priv->autoneg_cfg == AUTONEG_ENABLE) { err = mvEthSpeedDuplexSet(priv->hal_priv, MV_ETH_SPEED_AN, MV_ETH_DUPLEX_AN); /* Restart AN on PHY enables it */ if (!err) { err = mvEthPhyRestartAN(mv_phy_addr, MV_ETH_TOOL_AN_TIMEOUT); if (err == MV_TIMEOUT) { MV_ETH_PORT_STATUS ps; mvEthStatusGet(priv->hal_priv, &ps); if (!ps.isLinkUp) err = 0; } } } else if (priv->autoneg_cfg == AUTONEG_DISABLE) { err = mvEthPhyDisableAN(mv_phy_addr, mv_phy_speed, mv_phy_duplex); if (!err) { err = mvEthSpeedDuplexSet(priv->hal_priv, mv_mac_speed, mv_mac_duplex); } } else { err = -EINVAL; } return err; }