@@ -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,
@@ -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 */
@@ -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 */
@@ -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__ */
@@ -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;
}