Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: stmmac: Enable EEE HW LPI timer with auto SW/HW switching

This patch enables the HW LPI Timer which controls the automatic entry
and exit of the LPI state.
The EEE LPI timer value is configured through ethtool. The driver will
auto select the LPI HW timer if the value in the HW timer supported range.
Else, the driver will fallback to SW timer.

Signed-off-by: Vineetha G. Jaya Kumaran <vineetha.g.jaya.kumaran@intel.com>
Signed-off-by: Voon Weifeng <weifeng.voon@intel.com>
Link: https://lore.kernel.org/r/20201027160051.22898-1-weifeng.voon@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Vineetha G. Jaya Kumaran and committed by
Jakub Kicinski
be1c7eae 8911097f

+59 -3
+1
drivers/net/ethernet/stmicro/stmmac/common.h
··· 402 402 /* Default LPI timers */ 403 403 #define STMMAC_DEFAULT_LIT_LS 0x3E8 404 404 #define STMMAC_DEFAULT_TWT_LS 0x1E 405 + #define STMMAC_ET_MAX 0xFFFFF 405 406 406 407 #define STMMAC_CHAIN_MODE 0x1 407 408 #define STMMAC_RING_MODE 0x2
+2
drivers/net/ethernet/stmicro/stmmac/dwmac4.h
··· 176 176 */ 177 177 #define GMAC4_LPI_CTRL_STATUS 0xd0 178 178 #define GMAC4_LPI_TIMER_CTRL 0xd4 179 + #define GMAC4_LPI_ENTRY_TIMER 0xd8 179 180 180 181 /* LPI control and status defines */ 181 182 #define GMAC4_LPI_CTRL_STATUS_LPITCSE BIT(21) /* LPI Tx Clock Stop Enable */ 183 + #define GMAC4_LPI_CTRL_STATUS_LPIATE BIT(20) /* LPI Timer Enable */ 182 184 #define GMAC4_LPI_CTRL_STATUS_LPITXA BIT(19) /* Enable LPI TX Automate */ 183 185 #define GMAC4_LPI_CTRL_STATUS_PLS BIT(17) /* PHY Link Status */ 184 186 #define GMAC4_LPI_CTRL_STATUS_LPIEN BIT(16) /* LPI Enable */
+24
drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
··· 379 379 writel(value, ioaddr + GMAC4_LPI_CTRL_STATUS); 380 380 } 381 381 382 + static void dwmac4_set_eee_lpi_entry_timer(struct mac_device_info *hw, int et) 383 + { 384 + void __iomem *ioaddr = hw->pcsr; 385 + int value = et & STMMAC_ET_MAX; 386 + int regval; 387 + 388 + /* Program LPI entry timer value into register */ 389 + writel(value, ioaddr + GMAC4_LPI_ENTRY_TIMER); 390 + 391 + /* Enable/disable LPI entry timer */ 392 + regval = readl(ioaddr + GMAC4_LPI_CTRL_STATUS); 393 + regval |= GMAC4_LPI_CTRL_STATUS_LPIEN | GMAC4_LPI_CTRL_STATUS_LPITXA; 394 + 395 + if (et) 396 + regval |= GMAC4_LPI_CTRL_STATUS_LPIATE; 397 + else 398 + regval &= ~GMAC4_LPI_CTRL_STATUS_LPIATE; 399 + 400 + writel(regval, ioaddr + GMAC4_LPI_CTRL_STATUS); 401 + } 402 + 382 403 static void dwmac4_set_eee_timer(struct mac_device_info *hw, int ls, int tw) 383 404 { 384 405 void __iomem *ioaddr = hw->pcsr; ··· 1185 1164 .get_umac_addr = dwmac4_get_umac_addr, 1186 1165 .set_eee_mode = dwmac4_set_eee_mode, 1187 1166 .reset_eee_mode = dwmac4_reset_eee_mode, 1167 + .set_eee_lpi_entry_timer = dwmac4_set_eee_lpi_entry_timer, 1188 1168 .set_eee_timer = dwmac4_set_eee_timer, 1189 1169 .set_eee_pls = dwmac4_set_eee_pls, 1190 1170 .pcs_ctrl_ane = dwmac4_ctrl_ane, ··· 1228 1206 .get_umac_addr = dwmac4_get_umac_addr, 1229 1207 .set_eee_mode = dwmac4_set_eee_mode, 1230 1208 .reset_eee_mode = dwmac4_reset_eee_mode, 1209 + .set_eee_lpi_entry_timer = dwmac4_set_eee_lpi_entry_timer, 1231 1210 .set_eee_timer = dwmac4_set_eee_timer, 1232 1211 .set_eee_pls = dwmac4_set_eee_pls, 1233 1212 .pcs_ctrl_ane = dwmac4_ctrl_ane, ··· 1272 1249 .get_umac_addr = dwmac4_get_umac_addr, 1273 1250 .set_eee_mode = dwmac4_set_eee_mode, 1274 1251 .reset_eee_mode = dwmac4_reset_eee_mode, 1252 + .set_eee_lpi_entry_timer = dwmac4_set_eee_lpi_entry_timer, 1275 1253 .set_eee_timer = dwmac4_set_eee_timer, 1276 1254 .set_eee_pls = dwmac4_set_eee_pls, 1277 1255 .pcs_ctrl_ane = dwmac4_ctrl_ane,
+3
drivers/net/ethernet/stmicro/stmmac/hwif.h
··· 337 337 void (*set_eee_mode)(struct mac_device_info *hw, 338 338 bool en_tx_lpi_clockgating); 339 339 void (*reset_eee_mode)(struct mac_device_info *hw); 340 + void (*set_eee_lpi_entry_timer)(struct mac_device_info *hw, int et); 340 341 void (*set_eee_timer)(struct mac_device_info *hw, int ls, int tw); 341 342 void (*set_eee_pls)(struct mac_device_info *hw, int link); 342 343 void (*debug)(void __iomem *ioaddr, struct stmmac_extra_stats *x, ··· 440 439 stmmac_do_void_callback(__priv, mac, set_eee_mode, __args) 441 440 #define stmmac_reset_eee_mode(__priv, __args...) \ 442 441 stmmac_do_void_callback(__priv, mac, reset_eee_mode, __args) 442 + #define stmmac_set_eee_lpi_timer(__priv, __args...) \ 443 + stmmac_do_void_callback(__priv, mac, set_eee_lpi_entry_timer, __args) 443 444 #define stmmac_set_eee_timer(__priv, __args...) \ 444 445 stmmac_do_void_callback(__priv, mac, set_eee_timer, __args) 445 446 #define stmmac_set_eee_pls(__priv, __args...) \
+1
drivers/net/ethernet/stmicro/stmmac/stmmac.h
··· 207 207 int tx_lpi_timer; 208 208 int tx_lpi_enabled; 209 209 int eee_tw_timer; 210 + bool eee_sw_timer_en; 210 211 unsigned int mode; 211 212 unsigned int chain_mode; 212 213 int extend_desc;
+28 -3
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
··· 294 294 return dirty; 295 295 } 296 296 297 + static void stmmac_lpi_entry_timer_config(struct stmmac_priv *priv, bool en) 298 + { 299 + int tx_lpi_timer; 300 + 301 + /* Clear/set the SW EEE timer flag based on LPI ET enablement */ 302 + priv->eee_sw_timer_en = en ? 0 : 1; 303 + tx_lpi_timer = en ? priv->tx_lpi_timer : 0; 304 + stmmac_set_eee_lpi_timer(priv, priv->hw, tx_lpi_timer); 305 + } 306 + 297 307 /** 298 308 * stmmac_enable_eee_mode - check and enter in LPI mode 299 309 * @priv: driver private structure ··· 337 327 */ 338 328 void stmmac_disable_eee_mode(struct stmmac_priv *priv) 339 329 { 330 + if (!priv->eee_sw_timer_en) { 331 + stmmac_lpi_entry_timer_config(priv, 0); 332 + return; 333 + } 334 + 340 335 stmmac_reset_eee_mode(priv, priv->hw); 341 336 del_timer_sync(&priv->eee_ctrl_timer); 342 337 priv->tx_path_in_lpi_mode = false; ··· 391 376 if (!priv->eee_active) { 392 377 if (priv->eee_enabled) { 393 378 netdev_dbg(priv->dev, "disable EEE\n"); 379 + stmmac_lpi_entry_timer_config(priv, 0); 394 380 del_timer_sync(&priv->eee_ctrl_timer); 395 381 stmmac_set_eee_timer(priv, priv->hw, 0, eee_tw_timer); 396 382 } ··· 405 389 eee_tw_timer); 406 390 } 407 391 408 - mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(priv->tx_lpi_timer)); 392 + if (priv->plat->has_gmac4 && priv->tx_lpi_timer <= STMMAC_ET_MAX) { 393 + del_timer_sync(&priv->eee_ctrl_timer); 394 + priv->tx_path_in_lpi_mode = false; 395 + stmmac_lpi_entry_timer_config(priv, 1); 396 + } else { 397 + stmmac_lpi_entry_timer_config(priv, 0); 398 + mod_timer(&priv->eee_ctrl_timer, 399 + STMMAC_LPI_T(priv->tx_lpi_timer)); 400 + } 409 401 410 402 mutex_unlock(&priv->lock); 411 403 netdev_dbg(priv->dev, "Energy-Efficient Ethernet initialized\n"); ··· 2068 2044 netif_tx_wake_queue(netdev_get_tx_queue(priv->dev, queue)); 2069 2045 } 2070 2046 2071 - if ((priv->eee_enabled) && (!priv->tx_path_in_lpi_mode)) { 2047 + if (priv->eee_enabled && !priv->tx_path_in_lpi_mode && 2048 + priv->eee_sw_timer_en) { 2072 2049 stmmac_enable_eee_mode(priv); 2073 2050 mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(priv->tx_lpi_timer)); 2074 2051 } ··· 3331 3306 tx_q = &priv->tx_queue[queue]; 3332 3307 first_tx = tx_q->cur_tx; 3333 3308 3334 - if (priv->tx_path_in_lpi_mode) 3309 + if (priv->tx_path_in_lpi_mode && priv->eee_sw_timer_en) 3335 3310 stmmac_disable_eee_mode(priv); 3336 3311 3337 3312 /* Manage oversized TCP frames for GMAC4 device */