/****************************************************************************** * mv_eth_tool_get_pauseparam * Description: * ethtool get pause parameters * INPUT: * netdev Network device structure pointer * OUTPUT * pause Pause paranmeters * RETURN: * None * *******************************************************************************/ void mv_eth_tool_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) { struct eth_port *priv = MV_ETH_PRIV(netdev); int port = priv->port; MV_ETH_PORT_STATUS portStatus; MV_ETH_PORT_FC flowCtrl; if ((priv == NULL) || (isSwitch(priv)) || (MV_PON_PORT(priv->port))) { printk(KERN_ERR "%s is not supported on %s\n", __func__, netdev->name); return; } mvNetaFlowCtrlGet(port, &flowCtrl); if ((flowCtrl == MV_ETH_FC_AN_NO) || (flowCtrl == MV_ETH_FC_AN_SYM) || (flowCtrl == MV_ETH_FC_AN_ASYM)) pause->autoneg = AUTONEG_ENABLE; else pause->autoneg = AUTONEG_DISABLE; mvNetaLinkStatus(port, &portStatus); if (portStatus.rxFc == MV_ETH_FC_DISABLE) pause->rx_pause = 0; else pause->rx_pause = 1; if (portStatus.txFc == MV_ETH_FC_DISABLE) pause->tx_pause = 0; else pause->tx_pause = 1; }
/****************************************************************************** * mv_eth_tool_set_settings * Description: * ethtool set standard port settings * INPUT: * netdev Network device structure pointer * cmd command (settings) * OUTPUT * None * RETURN: * 0 for success * *******************************************************************************/ int mv_eth_tool_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct eth_port *priv = MV_ETH_PRIV(dev); int _speed, _duplex, _autoneg, _advertise, err; if ((priv == NULL) || (isSwitch(priv)) || (MV_PON_PORT(priv->port))) { printk(KERN_ERR "%s is not supported on %s\n", __func__, dev->name); return -EOPNOTSUPP; } _duplex = priv->duplex_cfg; _speed = priv->speed_cfg; _autoneg = priv->autoneg_cfg; _advertise = priv->advertise_cfg; priv->duplex_cfg = cmd->duplex; priv->speed_cfg = cmd->speed; priv->autoneg_cfg = cmd->autoneg; priv->advertise_cfg = cmd->advertising; err = mv_eth_tool_restore_settings(dev); if (err) { priv->duplex_cfg = _duplex; priv->speed_cfg = _speed; priv->autoneg_cfg = _autoneg; priv->advertise_cfg = _advertise; } return err; }
/****************************************************************************** * mv_eth_tool_get_settings * Description: * ethtool get standard port settings * INPUT: * netdev Network device structure pointer * OUTPUT * cmd command (settings) * RETURN: * 0 for success * *******************************************************************************/ int mv_eth_tool_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd) { struct eth_port *priv = MV_ETH_PRIV(netdev); MV_U32 mv_phy_addr; MV_ETH_PORT_SPEED speed; MV_ETH_PORT_DUPLEX duplex; MV_ETH_PORT_STATUS status; 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; } cmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII | SUPPORTED_1000baseT_Full); mv_phy_addr = mvBoardPhyAddrGet(priv->port); mvNetaLinkStatus(priv->port, &status); switch (status.speed) { case MV_ETH_SPEED_1000: cmd->speed = SPEED_1000; break; case MV_ETH_SPEED_100: cmd->speed = SPEED_100; break; case MV_ETH_SPEED_10: cmd->speed = SPEED_10; break; default: return -EINVAL; } if (status.duplex == MV_ETH_DUPLEX_FULL) cmd->duplex = 1; else cmd->duplex = 0; cmd->port = PORT_MII; cmd->phy_address = mv_phy_addr; cmd->transceiver = XCVR_INTERNAL; /* check if speed and duplex are AN */ mvNetaSpeedDuplexGet(priv->port, &speed, &duplex); if (speed == MV_ETH_SPEED_AN && duplex == MV_ETH_DUPLEX_AN) { /* Note: lp_advertising not available in this kernel */ cmd->advertising = 0; cmd->autoneg = AUTONEG_ENABLE; mvEthPhyAdvertiseGet(mv_phy_addr, (MV_U16 *)&(cmd->advertising)); } else cmd->autoneg = AUTONEG_DISABLE; return 0; }
/******************************************************************************* * mvEthMibCountersClear - Clear all MIB counters * * DESCRIPTION: * This function clears all MIB counters * * INPUT: * port - Ethernet Port number. * * RETURN: void * *******************************************************************************/ void mvEthMibCountersClear(int port) { int i; MV_U32 dummy; #if defined(CONFIG_MV_PON) && !defined(MV_PON_MIB_SUPPORT) if (MV_PON_PORT(port)) return; #endif /* CONFIG_MV_PON && !MV_PON_MIB_SUPPORT */ /* Perform dummy reads from MIB counters */ for (i = ETH_MIB_GOOD_OCTETS_RECEIVED_LOW; i < ETH_MIB_LATE_COLLISION; i += 4) dummy = MV_REG_READ((ETH_MIB_COUNTERS_BASE(port) + i)); }
MV_STATUS mvEthLinkStatus(int port, MV_ETH_PORT_STATUS *pStatus) { MV_U32 regVal; if (MV_PON_PORT(port)) { pStatus->linkup = MV_TRUE; pStatus->speed = MV_ETH_SPEED_1000; pStatus->duplex = MV_ETH_DUPLEX_FULL; pStatus->rxFc = MV_ETH_FC_DISABLE; pStatus->txFc = MV_ETH_FC_DISABLE; return MV_OK; } regVal = MV_REG_READ(ETH_GMAC_STATUS_REG(port)); if (regVal & ETH_GMAC_SPEED_1000_MASK) pStatus->speed = MV_ETH_SPEED_1000; else if (regVal & ETH_GMAC_SPEED_100_MASK) pStatus->speed = MV_ETH_SPEED_100; else pStatus->speed = MV_ETH_SPEED_10; if (regVal & ETH_GMAC_LINK_UP_MASK) pStatus->linkup = MV_TRUE; else pStatus->linkup = MV_FALSE; if (regVal & ETH_GMAC_FULL_DUPLEX_MASK) pStatus->duplex = MV_ETH_DUPLEX_FULL; else pStatus->duplex = MV_ETH_DUPLEX_HALF; if (regVal & ETH_TX_FLOW_CTRL_ACTIVE_MASK) pStatus->txFc = MV_ETH_FC_ACTIVE; else if (regVal & ETH_TX_FLOW_CTRL_ENABLE_MASK) pStatus->txFc = MV_ETH_FC_ENABLE; else pStatus->txFc = MV_ETH_FC_DISABLE; if (regVal & ETH_RX_FLOW_CTRL_ACTIVE_MASK) pStatus->rxFc = MV_ETH_FC_ACTIVE; else if (regVal & ETH_RX_FLOW_CTRL_ENABLE_MASK) pStatus->rxFc = MV_ETH_FC_ENABLE; else pStatus->rxFc = MV_ETH_FC_DISABLE; return MV_OK; }
/****************************************************************************** * 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; }
/******************************************************************************* * mvNetaMaxRxSizeSet - * * DESCRIPTION: * Change maximum receive size of the port. This configuration will take place * imidiately. * * INPUT: * * RETURN: *******************************************************************************/ void mvEthMaxRxSizeSet(int port, int maxRxSize) { MV_U32 regVal; if (!MV_PON_PORT(port)) { regVal = MV_REG_READ(ETH_GMAC_CTRL_0_REG(port)); regVal &= ~ETH_GMAC_MAX_RX_SIZE_MASK; regVal |= (((maxRxSize - MV_ETH_MH_SIZE) / 2) << ETH_GMAC_MAX_RX_SIZE_OFFS); mvPp2WrReg(ETH_GMAC_CTRL_0_REG(port), regVal); /* mvOsPrintf("%s: port=%d, maxRxSize=%d, regAddr=0x%x, regVal=0x%x\n", __func__, port, maxRxSize, ETH_GMAC_CTRL_0_REG(port), regVal); */ } }
/* Print MIB counters of the Ethernet port */ void mvEthMibCountersShow(int port) { if (MV_PON_PORT(port)) { mvOsPrintf("%s: not supported for PON port\n", __func__); return; } /*TODO: check port if (mvNetaTxpCheck(port)) return; */ mvOsPrintf("\nMIBs: port=%d\n", port); mvOsPrintf("\n[Rx]\n"); mvEthMibPrint(port, ETH_MIB_GOOD_FRAMES_RECEIVED, "GOOD_FRAMES_RECEIVED"); mvEthMibPrint(port, ETH_MIB_BAD_FRAMES_RECEIVED, "BAD_FRAMES_RECEIVED"); mvEthMibPrint(port, ETH_MIB_BROADCAST_FRAMES_RECEIVED, "BROADCAST_FRAMES_RECEIVED"); mvEthMibPrint(port, ETH_MIB_MULTICAST_FRAMES_RECEIVED, "MULTICAST_FRAMES_RECEIVED"); mvEthMibPrint(port, ETH_MIB_GOOD_OCTETS_RECEIVED_LOW, "GOOD_OCTETS_RECEIVED"); mvOsPrintf("\n[Rx Errors]\n"); mvEthMibPrint(port, ETH_MIB_BAD_OCTETS_RECEIVED, "BAD_OCTETS_RECEIVED"); mvEthMibPrint(port, ETH_MIB_UNDERSIZE_RECEIVED, "UNDERSIZE_RECEIVED"); mvEthMibPrint(port, ETH_MIB_FRAGMENTS_RECEIVED, "FRAGMENTS_RECEIVED"); mvEthMibPrint(port, ETH_MIB_OVERSIZE_RECEIVED, "OVERSIZE_RECEIVED"); mvEthMibPrint(port, ETH_MIB_JABBER_RECEIVED, "JABBER_RECEIVED"); mvEthMibPrint(port, ETH_MIB_MAC_RECEIVE_ERROR, "MAC_RECEIVE_ERROR"); mvEthMibPrint(port, ETH_MIB_BAD_CRC_EVENT, "BAD_CRC_EVENT"); mvOsPrintf("\n[Tx]\n"); mvEthMibPrint(port, ETH_MIB_GOOD_FRAMES_SENT, "GOOD_FRAMES_SENT"); mvEthMibPrint(port, ETH_MIB_BROADCAST_FRAMES_SENT, "BROADCAST_FRAMES_SENT"); mvEthMibPrint(port, ETH_MIB_MULTICAST_FRAMES_SENT, "MULTICAST_FRAMES_SENT"); mvEthMibPrint(port, ETH_MIB_GOOD_OCTETS_SENT_LOW, "GOOD_OCTETS_SENT"); mvOsPrintf("\n[Tx Errors]\n"); mvEthMibPrint(port, ETH_MIB_INTERNAL_MAC_TRANSMIT_ERR, "INTERNAL_MAC_TRANSMIT_ERR"); mvEthMibPrint(port, ETH_MIB_EXCESSIVE_COLLISION, "EXCESSIVE_COLLISION"); mvEthMibPrint(port, ETH_MIB_COLLISION, "COLLISION"); mvEthMibPrint(port, ETH_MIB_LATE_COLLISION, "LATE_COLLISION"); mvOsPrintf("\n[FC control]\n"); mvEthMibPrint(port, ETH_MIB_UNREC_MAC_CONTROL_RECEIVED, "UNREC_MAC_CONTROL_RECEIVED"); mvEthMibPrint(port, ETH_MIB_GOOD_FC_RECEIVED, "GOOD_FC_RECEIVED"); mvEthMibPrint(port, ETH_MIB_BAD_FC_RECEIVED, "BAD_FC_RECEIVED"); mvEthMibPrint(port, ETH_MIB_FC_SENT, "FC_SENT"); mvOsPrintf("\n"); }
/****************************************************************************** * mv_eth_tool_get_link * Description: * ethtool get link status * INPUT: * netdev Network device structure pointer * OUTPUT * None * RETURN: * 0 if link is down, 1 if link is up * *******************************************************************************/ u32 mv_eth_tool_get_link(struct net_device *netdev) { struct eth_port *pp = MV_ETH_PRIV(netdev); struct eth_netdev *dev_priv = MV_DEV_PRIV(netdev); if (pp == NULL) { printk(KERN_ERR "interface %s is not supported\n", netdev->name); return -EOPNOTSUPP; } if (isSwitch(pp)) { if (dev_priv == NULL) return -EOPNOTSUPP; return (dev_priv->link_map != 0); } #ifdef CONFIG_MV_PON if (MV_PON_PORT(pp->port)) return mv_pon_link_status(); #endif /* CONFIG_MV_PON */ return mvNetaLinkIsUp(pp->port); }
/****************************************************************************** * 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_get_regs * Description: * ethtool get registers array * INPUT: * netdev Network device structure pointer * regs registers information * OUTPUT * p registers array * RETURN: * None * *******************************************************************************/ void mv_eth_tool_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p) { struct eth_port *priv = MV_ETH_PRIV(netdev); uint32_t *regs_buff = p; if ((priv == NULL) || MV_PON_PORT(priv->port)) { printk(KERN_ERR "%s is not supported on %s\n", __func__, netdev->name); return; } memset(p, 0, MV_ETH_TOOL_REGS_LEN * sizeof(uint32_t)); regs->version = mvCtrlModelRevGet(); /* ETH port registers */ regs_buff[0] = MV_REG_READ(ETH_PORT_STATUS_REG(priv->port)); regs_buff[1] = MV_REG_READ(ETH_PORT_SERIAL_CTRL_REG(priv->port)); regs_buff[2] = MV_REG_READ(ETH_PORT_CONFIG_REG(priv->port)); regs_buff[3] = MV_REG_READ(ETH_PORT_CONFIG_EXTEND_REG(priv->port)); regs_buff[4] = MV_REG_READ(ETH_SDMA_CONFIG_REG(priv->port)); /* regs_buff[5] = MV_REG_READ(ETH_TX_FIFO_URGENT_THRESH_REG(priv->port)); */ regs_buff[6] = MV_REG_READ(ETH_RX_QUEUE_COMMAND_REG(priv->port)); /* regs_buff[7] = MV_REG_READ(ETH_TX_QUEUE_COMMAND_REG(priv->port)); */ regs_buff[8] = MV_REG_READ(ETH_INTR_CAUSE_REG(priv->port)); regs_buff[9] = MV_REG_READ(ETH_INTR_CAUSE_EXT_REG(priv->port)); regs_buff[10] = MV_REG_READ(ETH_INTR_MASK_REG(priv->port)); regs_buff[11] = MV_REG_READ(ETH_INTR_MASK_EXT_REG(priv->port)); /* ETH Unit registers */ regs_buff[16] = MV_REG_READ(ETH_PHY_ADDR_REG(priv->port)); regs_buff[17] = MV_REG_READ(ETH_UNIT_INTR_CAUSE_REG(priv->port)); regs_buff[18] = MV_REG_READ(ETH_UNIT_INTR_MASK_REG(priv->port)); regs_buff[19] = MV_REG_READ(ETH_UNIT_ERROR_ADDR_REG(priv->port)); regs_buff[20] = MV_REG_READ(ETH_UNIT_INT_ADDR_ERROR_REG(priv->port)); }