Add the get_eee() and set_eee() helpers to support the Energy-Efficient (EEE) feature in the Annapurna Labs Alpine driver. --- drivers/net/ethernet/annapurna/al_eth.c | 44 +++++++++++ drivers/net/ethernet/annapurna/al_hw_eth.h | 28 +++++++ drivers/net/ethernet/annapurna/al_hw_eth_ec_regs.h | 11 +++ .../net/ethernet/annapurna/al_hw_eth_mac_regs.h | 11 +++ drivers/net/ethernet/annapurna/al_hw_eth_main.c | 92 ++++++++++++++++++++++ 5 files changed, 186 insertions(+)
diff --git a/drivers/net/ethernet/annapurna/al_eth.c b/drivers/net/ethernet/annapurna/al_eth.c index d06a75a49ce5..674dafdb638a 100644 --- a/drivers/net/ethernet/annapurna/al_eth.c +++ b/drivers/net/ethernet/annapurna/al_eth.c @@ -2519,6 +2519,47 @@ static u32 al_eth_get_rxfh_indir_size(struct net_device *netdev) return AL_ETH_RX_RSS_TABLE_SIZE; } +static int al_eth_get_eee(struct net_device *netdev, + struct ethtool_eee *edata) +{ + struct al_eth_adapter *adapter = netdev_priv(netdev); + struct al_eth_eee_params params; + + if (!adapter->phy_exist) + return -EOPNOTSUPP; + + al_eth_eee_get(&adapter->hw_adapter, ¶ms); + + edata->eee_enabled = params.enable; + edata->tx_lpi_timer = params.tx_eee_timer; + + return phy_ethtool_get_eee(adapter->phydev, edata); +} + +static int al_eth_set_eee(struct net_device *netdev, + struct ethtool_eee *edata) +{ + struct al_eth_adapter *adapter = netdev_priv(netdev); + struct al_eth_eee_params params; + + struct phy_device *phydev; + + if (!adapter->phy_exist) + return -EOPNOTSUPP; + + phydev = mdiobus_get_phy(adapter->mdio_bus, adapter->phy_addr); + + phy_init_eee(phydev, 1); + + params.enable = edata->eee_enabled; + params.tx_eee_timer = edata->tx_lpi_timer; + params.min_interval = 10; + + al_eth_eee_config(&adapter->hw_adapter, ¶ms); + + return phy_ethtool_set_eee(phydev, edata); +} + static void al_eth_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) { @@ -2576,6 +2617,9 @@ static const struct ethtool_ops al_eth_ethtool_ops = { .set_pauseparam = al_eth_set_pauseparam, .get_rxnfc = al_eth_get_rxnfc, .get_rxfh_indir_size = al_eth_get_rxfh_indir_size, + + .get_eee = al_eth_get_eee, + .set_eee = al_eth_set_eee, }; static void al_eth_tx_csum(struct al_eth_ring *tx_ring, diff --git a/drivers/net/ethernet/annapurna/al_hw_eth.h b/drivers/net/ethernet/annapurna/al_hw_eth.h index a44f3f200838..2ef11de6b1db 100644 --- a/drivers/net/ethernet/annapurna/al_hw_eth.h +++ b/drivers/net/ethernet/annapurna/al_hw_eth.h @@ -884,6 +884,34 @@ int al_eth_filter_config(struct al_hw_eth_adapter *adapter, struct al_eth_filter int al_eth_flow_control_config(struct al_hw_eth_adapter *adapter, struct al_eth_flow_control_params *params); +struct al_eth_eee_params { + u8 enable; + u32 tx_eee_timer; /* time in cycles the interface delays prior to entering eee state */ + u32 min_interval; /* minimum interval in cycles between two eee states */ + u32 stop_cnt; /* time in cycles to stop Tx mac i/f after getting out of eee state */ + bool fast_wake; /* fast_wake is only applicable to 40/50G, otherwise the mode is deep_sleep */ +}; + +/* + * configure EEE mode + * @param adapter pointer to the private structure. + * @param params pointer to the eee input parameters. + * + * @return return 0 on success. otherwise on failure. + */ +int al_eth_eee_config(struct al_hw_eth_adapter *adapter, + struct al_eth_eee_params *params); + +/* + * get EEE configuration + * @param adapter pointer to the private structure. + * @param params pointer to the eee output parameters. + * + * @return return 0 on success. otherwise on failure. + */ +int al_eth_eee_get(struct al_hw_eth_adapter *adapter, + struct al_eth_eee_params *params); + /* enum for methods when updating systime using triggers */ enum al_eth_pth_update_method { AL_ETH_PTH_UPDATE_METHOD_SET = 0, /* Set the time in int/ext update time */ diff --git a/drivers/net/ethernet/annapurna/al_hw_eth_ec_regs.h b/drivers/net/ethernet/annapurna/al_hw_eth_ec_regs.h index c239ac1e8b6c..c9353012101e 100644 --- a/drivers/net/ethernet/annapurna/al_hw_eth_ec_regs.h +++ b/drivers/net/ethernet/annapurna/al_hw_eth_ec_regs.h @@ -1085,4 +1085,15 @@ struct al_ec_regs { /* Threshold high */ #define EC_EFC_RX_FIFO_HYST_TH_HIGH_SHIFT 16 +/* Use Ethernet controller Tx FIFO empty status for EEE control */ +#define EC_EEE_CFG_E_USE_EC_TX_FIFO BIT(2) +/* Use Ethernet controller Rx FIFO empty status for EEE control */ +#define EC_EEE_CFG_E_USE_EC_RX_FIFO BIT(3) +/* Enable Low power signalling. */ +#define EC_EEE_CFG_E_ENABLE BIT(4) +/* Mask output to MAC. */ +#define EC_EEE_CFG_E_MASK_MAC_EEE BIT(8) +/* Mask output to stop MAC interface. */ +#define EC_EEE_CFG_E_MASK_EC_TMI_STOP BIT(9) + #endif /* __AL_HW_EC_REG_H */ diff --git a/drivers/net/ethernet/annapurna/al_hw_eth_mac_regs.h b/drivers/net/ethernet/annapurna/al_hw_eth_mac_regs.h index b2b956b7e28f..4201f3c4b01f 100644 --- a/drivers/net/ethernet/annapurna/al_hw_eth_mac_regs.h +++ b/drivers/net/ethernet/annapurna/al_hw_eth_mac_regs.h @@ -692,6 +692,10 @@ struct al_eth_mac_regs { /* LED default value */ #define ETH_MAC_GEN_LED_CFG_DEF BIT(4) +/* EEE timer value */ +#define ETH_MAC_KR_PCS_CFG_EEE_TIMER_VAL_MASK 0x0000FF00 +#define ETH_MAC_KR_PCS_CFG_EEE_TIMER_VAL_SHIFT 8 + #define ETH_MAC_SGMII_REG_ADDR_CTRL_REG 0x0 #define ETH_MAC_SGMII_REG_ADDR_IF_MODE_REG 0x14 @@ -703,6 +707,10 @@ struct al_eth_mac_regs { #define ETH_MAC_SGMII_REG_DATA_IF_MODE_SGMII_SPEED_1000 0x2 #define ETH_MAC_SGMII_REG_DATA_IF_MODE_SGMII_DUPLEX BIT(4) +/* Low power timer configuration */ +#define ETH_MAC_GEN_V3_PCS_40G_LL_EEE_CFG_TIMER_VAL_MASK 0x000000FF +#define ETH_MAC_GEN_V3_PCS_40G_LL_EEE_CFG_TIMER_VAL_SHIFT 0 + /* command config */ #define ETH_MAC_GEN_V3_MAC_40G_COMMAND_CONFIG_ADDR 0x00000008 #define ETH_MAC_GEN_V3_MAC_40G_COMMAND_CONFIG_TX_ENA BIT(0) @@ -724,4 +732,7 @@ struct al_eth_mac_regs { /* spare */ #define ETH_MAC_GEN_V3_SPARE_CHICKEN_DISABLE_TIMESTAMP_STRETCH BIT(0) +/* 40g EEE control and capability */ +#define ETH_MAC_GEN_V3_PCS_40G_EEE_CONTROL_ADDR 0x00000028 + #endif /* __AL_HW_ETH_MAC_REGS_H__ */ diff --git a/drivers/net/ethernet/annapurna/al_hw_eth_main.c b/drivers/net/ethernet/annapurna/al_hw_eth_main.c index dac0c1e2a941..99ed601332da 100644 --- a/drivers/net/ethernet/annapurna/al_hw_eth_main.c +++ b/drivers/net/ethernet/annapurna/al_hw_eth_main.c @@ -20,6 +20,12 @@ #define AL_ADDR_LOW(x) ((u32)((dma_addr_t)(x))) #define AL_ADDR_HIGH(x) ((u32)((((dma_addr_t)(x)) >> 16) >> 16)) +/* Number of xfi_txclk cycles that accumulate into 100ns */ +#define ETH_MAC_KR_10_PCS_CFG_EEE_TIMER_VAL 52 +#define ETH_MAC_KR_25_PCS_CFG_EEE_TIMER_VAL 80 +#define ETH_MAC_XLG_40_PCS_CFG_EEE_TIMER_VAL 63 +#define ETH_MAC_XLG_50_PCS_CFG_EEE_TIMER_VAL 85 + #define AL_ETH_TX_PKT_UDMA_FLAGS (AL_ETH_TX_FLAGS_NO_SNOOP | \ AL_ETH_TX_FLAGS_INT) @@ -2639,6 +2645,89 @@ int al_eth_flow_control_config(struct al_hw_eth_adapter *adapter, return 0; } +int al_eth_eee_get(struct al_hw_eth_adapter *adapter, + struct al_eth_eee_params *params) +{ + u32 reg; + + netdev_dbg(adapter->netdev, "[%s]: getting eee.\n", adapter->name); + + reg = readl(&adapter->ec_regs_base->eee.cfg_e); + params->enable = (reg & EC_EEE_CFG_E_ENABLE) ? true : false; + + params->tx_eee_timer = readl(&adapter->ec_regs_base->eee.pre_cnt); + params->min_interval = readl(&adapter->ec_regs_base->eee.post_cnt); + params->stop_cnt = readl(&adapter->ec_regs_base->eee.stop_cnt); + + return 0; +} + +int al_eth_eee_config(struct al_hw_eth_adapter *adapter, + struct al_eth_eee_params *params) +{ + u32 reg; + + netdev_dbg(adapter->netdev, "[%s]: config eee.\n", adapter->name); + + if (params->enable == 0) { + netdev_dbg(adapter->netdev, "[%s]: disable eee.\n", + adapter->name); + writel(0, &adapter->ec_regs_base->eee.cfg_e); + return 0; + } + if (AL_ETH_IS_10G_MAC(adapter->mac_mode) || AL_ETH_IS_25G_MAC(adapter->mac_mode)) { + reg = readl(&adapter->mac_regs_base->kr.pcs_cfg); + reg &= ~ETH_MAC_KR_PCS_CFG_EEE_TIMER_VAL_MASK; + reg |= (AL_ETH_IS_10G_MAC(adapter->mac_mode) ? + ETH_MAC_KR_10_PCS_CFG_EEE_TIMER_VAL : + ETH_MAC_KR_25_PCS_CFG_EEE_TIMER_VAL) << + ETH_MAC_KR_PCS_CFG_EEE_TIMER_VAL_SHIFT, + writel(reg, &adapter->mac_regs_base->kr.pcs_cfg); + } + if ((adapter->mac_mode == AL_ETH_MAC_MODE_XLG_LL_40G) || + (adapter->mac_mode == AL_ETH_MAC_MODE_XLG_LL_50G)) { + reg = readl(&adapter->mac_regs_base->gen_v3.pcs_40g_ll_eee_cfg); + reg &= ~ETH_MAC_GEN_V3_PCS_40G_LL_EEE_CFG_TIMER_VAL_MASK; + reg |= ((adapter->mac_mode == AL_ETH_MAC_MODE_XLG_LL_40G) ? + ETH_MAC_XLG_40_PCS_CFG_EEE_TIMER_VAL : + ETH_MAC_XLG_50_PCS_CFG_EEE_TIMER_VAL) << + ETH_MAC_GEN_V3_PCS_40G_LL_EEE_CFG_TIMER_VAL_SHIFT; + writel(reg, &adapter->mac_regs_base->gen_v3.pcs_40g_ll_eee_cfg); + + /* set Deep sleep mode as the LPI function (instead of Fast wake mode) */ + al_eth_40g_pcs_reg_write(adapter, ETH_MAC_GEN_V3_PCS_40G_EEE_CONTROL_ADDR, + params->fast_wake ? 1 : 0); + } + + writel(params->tx_eee_timer, &adapter->ec_regs_base->eee.pre_cnt); + writel(params->min_interval, &adapter->ec_regs_base->eee.post_cnt); + writel(params->stop_cnt, &adapter->ec_regs_base->eee.stop_cnt); + + reg = EC_EEE_CFG_E_MASK_EC_TMI_STOP | EC_EEE_CFG_E_MASK_MAC_EEE | + EC_EEE_CFG_E_ENABLE | EC_EEE_CFG_E_USE_EC_TX_FIFO | + EC_EEE_CFG_E_USE_EC_RX_FIFO; + + /* + * Addressing RMN: 3732 + * + * RMN description: + * When the HW get into eee mode, it can't transmit any pause packet + * (when flow control policy is enabled). + * In such case, the HW has no way to handle extreme pushback from + * the Rx_path fifos. + * + * Software flow: + * Configure RX_FIFO empty as eee mode term. + * That way, nothing will prevent pause packet transmittion in + * case of extreme pushback from the Rx_path fifos. + * + */ + + writel(reg, &adapter->ec_regs_base->eee.cfg_e); + + return 0; +} + /* get statistics */ int al_eth_mac_stats_get(struct al_hw_eth_adapter *adapter, struct al_eth_mac_stats *stats) { @@ -2860,6 +2949,9 @@ int al_eth_mac_stats_get(struct al_hw_eth_adapter *adapter, struct al_eth_mac_st stats->etherStatsPkts1519toX = _40g_mac_reg_read32(®_rx_stats->etherStatsPkts1519toMax); } + stats->eee_in = readl(&adapter->mac_regs_base->stat.eee_in); + stats->eee_out = readl(&adapter->mac_regs_base->stat.eee_out); + /* stats->etherStatsPkts = 1; */ return 0; } -- 2.11.0