net: stmmac: add new MAC method set_lpi_mode()

Add a new method to control LPI mode configuration. This is architected
to have three configuration states: LPI disabled, LPI forced (active),
or LPI under hardware timer control. This reflects the three modes
which the main body of the driver wishes to deal with.

We pass in whether transmit clock gating should be used, and the
hardware timer value in microseconds to be set when using hardware
timer control.

Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Link: https://patch.msgid.link/E1tffds-003ZIT-E8@rmk-PC.armlinux.org.uk
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Russell King (Oracle)
2025-02-05 13:40:36 +00:00
committed by Jakub Kicinski
parent 6e37877d22
commit 395c92c0fe
4 changed files with 103 additions and 62 deletions

View File

@@ -342,31 +342,35 @@ static int dwmac1000_irq_status(struct mac_device_info *hw,
return ret;
}
static void dwmac1000_set_eee_mode(struct mac_device_info *hw,
bool en_tx_lpi_clockgating)
static int dwmac1000_set_lpi_mode(struct mac_device_info *hw,
enum stmmac_lpi_mode mode,
bool en_tx_lpi_clockgating, u32 et)
{
void __iomem *ioaddr = hw->pcsr;
u32 value;
/*TODO - en_tx_lpi_clockgating treatment */
if (mode == STMMAC_LPI_TIMER)
return -EOPNOTSUPP;
/* Enable the link status receive on RGMII, SGMII ore SMII
* receive path and instruct the transmit to enter in LPI
* state.
*/
value = readl(ioaddr + LPI_CTRL_STATUS);
value |= LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA;
if (mode == STMMAC_LPI_FORCED)
value |= LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA;
else
value &= ~(LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA);
writel(value, ioaddr + LPI_CTRL_STATUS);
return 0;
}
static void dwmac1000_set_eee_mode(struct mac_device_info *hw,
bool en_tx_lpi_clockgating)
{
dwmac1000_set_lpi_mode(hw, STMMAC_LPI_FORCED, en_tx_lpi_clockgating, 0);
}
static void dwmac1000_reset_eee_mode(struct mac_device_info *hw)
{
void __iomem *ioaddr = hw->pcsr;
u32 value;
value = readl(ioaddr + LPI_CTRL_STATUS);
value &= ~(LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA);
writel(value, ioaddr + LPI_CTRL_STATUS);
dwmac1000_set_lpi_mode(hw, STMMAC_LPI_DISABLE, false, 0);
}
static void dwmac1000_set_eee_pls(struct mac_device_info *hw, int link)
@@ -509,6 +513,7 @@ const struct stmmac_ops dwmac1000_ops = {
.pmt = dwmac1000_pmt,
.set_umac_addr = dwmac1000_set_umac_addr,
.get_umac_addr = dwmac1000_get_umac_addr,
.set_lpi_mode = dwmac1000_set_lpi_mode,
.set_eee_mode = dwmac1000_set_eee_mode,
.reset_eee_mode = dwmac1000_reset_eee_mode,
.set_eee_timer = dwmac1000_set_eee_timer,

View File

@@ -376,35 +376,61 @@ static void dwmac4_get_umac_addr(struct mac_device_info *hw,
GMAC_ADDR_LOW(reg_n));
}
static int dwmac4_set_lpi_mode(struct mac_device_info *hw,
enum stmmac_lpi_mode mode,
bool en_tx_lpi_clockgating, u32 et)
{
void __iomem *ioaddr = hw->pcsr;
u32 value, mask;
if (mode == STMMAC_LPI_DISABLE) {
value = 0;
} else {
value = LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA;
if (mode == STMMAC_LPI_TIMER) {
/* Return ERANGE if the timer is larger than the
* register field.
*/
if (et > STMMAC_ET_MAX)
return -ERANGE;
/* Set the hardware LPI entry timer */
writel(et, ioaddr + GMAC4_LPI_ENTRY_TIMER);
/* Interpret a zero LPI entry timer to mean
* immediate entry into LPI mode.
*/
if (et)
value |= LPI_CTRL_STATUS_LPIATE;
}
if (en_tx_lpi_clockgating)
value |= LPI_CTRL_STATUS_LPITCSE;
}
mask = LPI_CTRL_STATUS_LPIATE | LPI_CTRL_STATUS_LPIEN |
LPI_CTRL_STATUS_LPITXA;
value |= readl(ioaddr + GMAC4_LPI_CTRL_STATUS) & ~mask;
writel(value, ioaddr + GMAC4_LPI_CTRL_STATUS);
return 0;
}
static void dwmac4_set_eee_mode(struct mac_device_info *hw,
bool en_tx_lpi_clockgating)
{
void __iomem *ioaddr = hw->pcsr;
u32 value;
/* Enable the link status receive on RGMII, SGMII ore SMII
* receive path and instruct the transmit to enter in LPI
* state.
*/
value = readl(ioaddr + GMAC4_LPI_CTRL_STATUS);
value &= ~LPI_CTRL_STATUS_LPIATE;
value |= LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA;
if (en_tx_lpi_clockgating)
value |= LPI_CTRL_STATUS_LPITCSE;
writel(value, ioaddr + GMAC4_LPI_CTRL_STATUS);
dwmac4_set_lpi_mode(hw, STMMAC_LPI_FORCED, en_tx_lpi_clockgating, 0);
}
static void dwmac4_reset_eee_mode(struct mac_device_info *hw)
{
void __iomem *ioaddr = hw->pcsr;
u32 value;
value = readl(ioaddr + GMAC4_LPI_CTRL_STATUS);
value &= ~(LPI_CTRL_STATUS_LPIATE | LPI_CTRL_STATUS_LPIEN |
LPI_CTRL_STATUS_LPITXA);
writel(value, ioaddr + GMAC4_LPI_CTRL_STATUS);
dwmac4_set_lpi_mode(hw, STMMAC_LPI_DISABLE, false, 0);
}
static void dwmac4_set_eee_pls(struct mac_device_info *hw, int link)
@@ -424,23 +450,7 @@ static void dwmac4_set_eee_pls(struct mac_device_info *hw, int link)
static void dwmac4_set_eee_lpi_entry_timer(struct mac_device_info *hw, u32 et)
{
void __iomem *ioaddr = hw->pcsr;
u32 value = et & STMMAC_ET_MAX;
int regval;
/* Program LPI entry timer value into register */
writel(value, ioaddr + GMAC4_LPI_ENTRY_TIMER);
/* Enable/disable LPI entry timer */
regval = readl(ioaddr + GMAC4_LPI_CTRL_STATUS);
regval |= LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA;
if (et)
regval |= LPI_CTRL_STATUS_LPIATE;
else
regval &= ~LPI_CTRL_STATUS_LPIATE;
writel(regval, ioaddr + GMAC4_LPI_CTRL_STATUS);
dwmac4_set_lpi_mode(hw, STMMAC_LPI_TIMER, false, et & STMMAC_ET_MAX);
}
static void dwmac4_set_eee_timer(struct mac_device_info *hw, int ls, int tw)
@@ -1203,6 +1213,7 @@ const struct stmmac_ops dwmac4_ops = {
.pmt = dwmac4_pmt,
.set_umac_addr = dwmac4_set_umac_addr,
.get_umac_addr = dwmac4_get_umac_addr,
.set_lpi_mode = dwmac4_set_lpi_mode,
.set_eee_mode = dwmac4_set_eee_mode,
.reset_eee_mode = dwmac4_reset_eee_mode,
.set_eee_lpi_entry_timer = dwmac4_set_eee_lpi_entry_timer,
@@ -1247,6 +1258,7 @@ const struct stmmac_ops dwmac410_ops = {
.pmt = dwmac4_pmt,
.set_umac_addr = dwmac4_set_umac_addr,
.get_umac_addr = dwmac4_get_umac_addr,
.set_lpi_mode = dwmac4_set_lpi_mode,
.set_eee_mode = dwmac4_set_eee_mode,
.reset_eee_mode = dwmac4_reset_eee_mode,
.set_eee_lpi_entry_timer = dwmac4_set_eee_lpi_entry_timer,
@@ -1293,6 +1305,7 @@ const struct stmmac_ops dwmac510_ops = {
.pmt = dwmac4_pmt,
.set_umac_addr = dwmac4_set_umac_addr,
.get_umac_addr = dwmac4_get_umac_addr,
.set_lpi_mode = dwmac4_set_lpi_mode,
.set_eee_mode = dwmac4_set_eee_mode,
.reset_eee_mode = dwmac4_reset_eee_mode,
.set_eee_lpi_entry_timer = dwmac4_set_eee_lpi_entry_timer,

View File

@@ -425,29 +425,39 @@ static void dwxgmac2_get_umac_addr(struct mac_device_info *hw,
addr[5] = (hi_addr >> 8) & 0xff;
}
static void dwxgmac2_set_eee_mode(struct mac_device_info *hw,
bool en_tx_lpi_clockgating)
static int dwxgmac2_set_lpi_mode(struct mac_device_info *hw,
enum stmmac_lpi_mode mode,
bool en_tx_lpi_clockgating, u32 et)
{
void __iomem *ioaddr = hw->pcsr;
u32 value;
if (mode == STMMAC_LPI_TIMER)
return -EOPNOTSUPP;
value = readl(ioaddr + XGMAC_LPI_CTRL);
value |= LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA;
if (en_tx_lpi_clockgating)
value |= LPI_CTRL_STATUS_LPITCSE;
if (mode == STMMAC_LPI_FORCED) {
value |= LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA;
if (en_tx_lpi_clockgating)
value |= LPI_CTRL_STATUS_LPITCSE;
} else {
value &= ~(LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA |
LPI_CTRL_STATUS_LPITCSE);
}
writel(value, ioaddr + XGMAC_LPI_CTRL);
return 0;
}
static void dwxgmac2_set_eee_mode(struct mac_device_info *hw,
bool en_tx_lpi_clockgating)
{
dwxgmac2_set_lpi_mode(hw, STMMAC_LPI_FORCED, en_tx_lpi_clockgating, 0);
}
static void dwxgmac2_reset_eee_mode(struct mac_device_info *hw)
{
void __iomem *ioaddr = hw->pcsr;
u32 value;
value = readl(ioaddr + XGMAC_LPI_CTRL);
value &= ~(LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA | LPI_CTRL_STATUS_LPITCSE);
writel(value, ioaddr + XGMAC_LPI_CTRL);
dwxgmac2_set_lpi_mode(hw, STMMAC_LPI_DISABLE, false, 0);
}
static void dwxgmac2_set_eee_pls(struct mac_device_info *hw, int link)
@@ -1525,6 +1535,7 @@ const struct stmmac_ops dwxgmac210_ops = {
.pmt = dwxgmac2_pmt,
.set_umac_addr = dwxgmac2_set_umac_addr,
.get_umac_addr = dwxgmac2_get_umac_addr,
.set_lpi_mode = dwxgmac2_set_lpi_mode,
.set_eee_mode = dwxgmac2_set_eee_mode,
.reset_eee_mode = dwxgmac2_reset_eee_mode,
.set_eee_timer = dwxgmac2_set_eee_timer,
@@ -1582,6 +1593,7 @@ const struct stmmac_ops dwxlgmac2_ops = {
.pmt = dwxgmac2_pmt,
.set_umac_addr = dwxgmac2_set_umac_addr,
.get_umac_addr = dwxgmac2_get_umac_addr,
.set_lpi_mode = dwxgmac2_set_lpi_mode,
.set_eee_mode = dwxgmac2_set_eee_mode,
.reset_eee_mode = dwxgmac2_reset_eee_mode,
.set_eee_timer = dwxgmac2_set_eee_timer,

View File

@@ -306,6 +306,12 @@ struct stmmac_pps_cfg;
struct stmmac_rss;
struct stmmac_est;
enum stmmac_lpi_mode {
STMMAC_LPI_DISABLE,
STMMAC_LPI_FORCED,
STMMAC_LPI_TIMER,
};
/* Helpers to program the MAC core */
struct stmmac_ops {
/* MAC core initialization */
@@ -360,6 +366,9 @@ struct stmmac_ops {
unsigned int reg_n);
void (*get_umac_addr)(struct mac_device_info *hw, unsigned char *addr,
unsigned int reg_n);
int (*set_lpi_mode)(struct mac_device_info *hw,
enum stmmac_lpi_mode mode,
bool en_tx_lpi_clockgating, u32 et);
void (*set_eee_mode)(struct mac_device_info *hw,
bool en_tx_lpi_clockgating);
void (*reset_eee_mode)(struct mac_device_info *hw);
@@ -467,6 +476,8 @@ struct stmmac_ops {
stmmac_do_void_callback(__priv, mac, set_umac_addr, __args)
#define stmmac_get_umac_addr(__priv, __args...) \
stmmac_do_void_callback(__priv, mac, get_umac_addr, __args)
#define stmmac_set_lpi_mode(__priv, __args...) \
stmmac_do_callback(__priv, mac, set_lpi_mode, __args)
#define stmmac_set_eee_mode(__priv, __args...) \
stmmac_do_void_callback(__priv, mac, set_eee_mode, __args)
#define stmmac_reset_eee_mode(__priv, __args...) \