From ef2c0a78aee10113d1299eb81e642470308e32ca Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 30 Apr 2020 21:55:36 +0200 Subject: r8169: don't pass net_device to irq coalescing sub-functions The net_device argument is just used to get a struct rtl8169_private pointer via netdev_priv(). Therefore pass the struct rtl8169_private pointer directly. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_main.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 68d5255568a5..1c3974ad88eb 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -1805,9 +1805,9 @@ static const struct rtl_coalesce_info rtl_coalesce_info_8168_8136[] = { #undef rxtx_x1822 /* get rx/tx scale vector corresponding to current speed */ -static const struct rtl_coalesce_info *rtl_coalesce_info(struct net_device *dev) +static const struct rtl_coalesce_info * +rtl_coalesce_info(struct rtl8169_private *tp) { - struct rtl8169_private *tp = netdev_priv(dev); const struct rtl_coalesce_info *ci; if (tp->mac_version <= RTL_GIGA_MAC_VER_06) @@ -1844,7 +1844,7 @@ static int rtl_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) memset(ec, 0, sizeof(*ec)); /* get rx/tx scale corresponding to current speed and CPlusCmd[0:1] */ - ci = rtl_coalesce_info(dev); + ci = rtl_coalesce_info(tp); if (IS_ERR(ci)) return PTR_ERR(ci); @@ -1874,12 +1874,12 @@ static int rtl_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) /* choose appropriate scale factor and CPlusCmd[0:1] for (speed, nsec) */ static const struct rtl_coalesce_scale *rtl_coalesce_choose_scale( - struct net_device *dev, u32 nsec, u16 *cp01) + struct rtl8169_private *tp, u32 nsec, u16 *cp01) { const struct rtl_coalesce_info *ci; u16 i; - ci = rtl_coalesce_info(dev); + ci = rtl_coalesce_info(tp); if (IS_ERR(ci)) return ERR_CAST(ci); @@ -1912,7 +1912,7 @@ static int rtl_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) if (rtl_is_8125(tp)) return -EOPNOTSUPP; - scale = rtl_coalesce_choose_scale(dev, + scale = rtl_coalesce_choose_scale(tp, max(p[0].usecs, p[1].usecs) * 1000, &cp01); if (IS_ERR(scale)) return PTR_ERR(scale); -- cgit v1.2.3 From 2815b30535a0613ee07d477d0c628100f40b6059 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 30 Apr 2020 21:56:20 +0200 Subject: r8169: merge scale for tx and rx irq coalescing Rx and tx scale are the same always. Simplify the code by using one scale for rx and tx only. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_main.c | 65 ++++++++++++------------------- 1 file changed, 25 insertions(+), 40 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 1c3974ad88eb..9932b6ffae02 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -1768,41 +1768,29 @@ static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data) * 1 1 160us 81.92us 1.31ms */ -/* rx/tx scale factors for one particular CPlusCmd[0:1] value */ -struct rtl_coalesce_scale { - /* Rx / Tx */ - u32 nsecs[2]; -}; - /* rx/tx scale factors for all CPlusCmd[0:1] cases */ struct rtl_coalesce_info { u32 speed; - struct rtl_coalesce_scale scalev[4]; /* each CPlusCmd[0:1] case */ + u32 scale_nsecs[4]; }; -/* produce (r,t) pairs with each being in series of *1, *8, *8*2, *8*2*2 */ -#define rxtx_x1822(r, t) { \ - {{(r), (t)}}, \ - {{(r)*8, (t)*8}}, \ - {{(r)*8*2, (t)*8*2}}, \ - {{(r)*8*2*2, (t)*8*2*2}}, \ -} +/* produce array with base delay *1, *8, *8*2, *8*2*2 */ +#define COALESCE_DELAY(d) { (d), 8 * (d), 16 * (d), 32 * (d) } + static const struct rtl_coalesce_info rtl_coalesce_info_8169[] = { - /* speed delays: rx00 tx00 */ - { SPEED_10, rxtx_x1822(40960, 40960) }, - { SPEED_100, rxtx_x1822( 2560, 2560) }, - { SPEED_1000, rxtx_x1822( 320, 320) }, + { SPEED_10, COALESCE_DELAY(40960) }, + { SPEED_100, COALESCE_DELAY(2560) }, + { SPEED_1000, COALESCE_DELAY(320) }, { 0 }, }; static const struct rtl_coalesce_info rtl_coalesce_info_8168_8136[] = { - /* speed delays: rx00 tx00 */ - { SPEED_10, rxtx_x1822(40960, 40960) }, - { SPEED_100, rxtx_x1822( 2560, 2560) }, - { SPEED_1000, rxtx_x1822( 5000, 5000) }, + { SPEED_10, COALESCE_DELAY(40960) }, + { SPEED_100, COALESCE_DELAY(2560) }, + { SPEED_1000, COALESCE_DELAY(5000) }, { 0 }, }; -#undef rxtx_x1822 +#undef COALESCE_DELAY /* get rx/tx scale vector corresponding to current speed */ static const struct rtl_coalesce_info * @@ -1827,7 +1815,6 @@ static int rtl_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) { struct rtl8169_private *tp = netdev_priv(dev); const struct rtl_coalesce_info *ci; - const struct rtl_coalesce_scale *scale; struct { u32 *max_frames; u32 *usecs; @@ -1835,6 +1822,7 @@ static int rtl_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) { &ec->rx_max_coalesced_frames, &ec->rx_coalesce_usecs }, { &ec->tx_max_coalesced_frames, &ec->tx_coalesce_usecs } }, *p = coal_settings; + u32 scale; int i; u16 w; @@ -1848,7 +1836,7 @@ static int rtl_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) if (IS_ERR(ci)) return PTR_ERR(ci); - scale = &ci->scalev[tp->cp_cmd & INTT_MASK]; + scale = ci->scale_nsecs[tp->cp_cmd & INTT_MASK]; /* read IntrMitigate and adjust according to scale */ for (w = RTL_R16(tp, IntrMitigate); w; w >>= RTL_COALESCE_SHIFT, p++) { @@ -1859,7 +1847,7 @@ static int rtl_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) for (i = 0; i < 2; i++) { p = coal_settings + i; - *p->usecs = (*p->usecs * scale->nsecs[i]) / 1000; + *p->usecs = (*p->usecs * scale) / 1000; /* * ethtool_coalesce says it is illegal to set both usecs and @@ -1873,32 +1861,29 @@ static int rtl_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) } /* choose appropriate scale factor and CPlusCmd[0:1] for (speed, nsec) */ -static const struct rtl_coalesce_scale *rtl_coalesce_choose_scale( - struct rtl8169_private *tp, u32 nsec, u16 *cp01) +static int rtl_coalesce_choose_scale(struct rtl8169_private *tp, u32 nsec, + u16 *cp01) { const struct rtl_coalesce_info *ci; u16 i; ci = rtl_coalesce_info(tp); if (IS_ERR(ci)) - return ERR_CAST(ci); + return PTR_ERR(ci); for (i = 0; i < 4; i++) { - u32 rxtx_maxscale = max(ci->scalev[i].nsecs[0], - ci->scalev[i].nsecs[1]); - if (nsec <= rxtx_maxscale * RTL_COALESCE_T_MAX) { + if (nsec <= ci->scale_nsecs[i] * RTL_COALESCE_T_MAX) { *cp01 = i; - return &ci->scalev[i]; + return ci->scale_nsecs[i]; } } - return ERR_PTR(-EINVAL); + return -EINVAL; } static int rtl_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) { struct rtl8169_private *tp = netdev_priv(dev); - const struct rtl_coalesce_scale *scale; struct { u32 frames; u32 usecs; @@ -1906,16 +1891,16 @@ static int rtl_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) { ec->rx_max_coalesced_frames, ec->rx_coalesce_usecs }, { ec->tx_max_coalesced_frames, ec->tx_coalesce_usecs } }, *p = coal_settings; - u16 w = 0, cp01; - int i; + u16 w = 0, cp01 = 0; + int scale, i; if (rtl_is_8125(tp)) return -EOPNOTSUPP; scale = rtl_coalesce_choose_scale(tp, max(p[0].usecs, p[1].usecs) * 1000, &cp01); - if (IS_ERR(scale)) - return PTR_ERR(scale); + if (scale < 0) + return scale; for (i = 0; i < 2; i++, p++) { u32 units; @@ -1936,7 +1921,7 @@ static int rtl_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) p->frames = 0; } - units = p->usecs * 1000 / scale->nsecs[i]; + units = p->usecs * 1000 / scale; if (p->frames > RTL_COALESCE_FRAME_MAX || p->frames % 4) return -EINVAL; -- cgit v1.2.3 From 6cf96dd4272537baf4ceab452f6276da1b8d82af Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 30 Apr 2020 21:56:58 +0200 Subject: r8169: improve rtl_get_coalesce Use FIELD_GET() macro to make the code better readable. In addition change the logic to round the time limit up, not down. Reason is that a time limit <1us would be rounded to 0 currently, what would be interpreted as "no time limit set". Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_main.c | 46 ++++++++++++++----------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 9932b6ffae02..a36a48f713fa 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -229,6 +230,11 @@ enum rtl_registers { CPlusCmd = 0xe0, IntrMitigate = 0xe2, +#define RTL_COALESCE_TX_USECS GENMASK(15, 12) +#define RTL_COALESCE_TX_FRAMES GENMASK(11, 8) +#define RTL_COALESCE_RX_USECS GENMASK(7, 4) +#define RTL_COALESCE_RX_FRAMES GENMASK(3, 0) + #define RTL_COALESCE_MASK 0x0f #define RTL_COALESCE_SHIFT 4 #define RTL_COALESCE_T_MAX (RTL_COALESCE_MASK) @@ -1815,16 +1821,8 @@ static int rtl_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) { struct rtl8169_private *tp = netdev_priv(dev); const struct rtl_coalesce_info *ci; - struct { - u32 *max_frames; - u32 *usecs; - } coal_settings [] = { - { &ec->rx_max_coalesced_frames, &ec->rx_coalesce_usecs }, - { &ec->tx_max_coalesced_frames, &ec->tx_coalesce_usecs } - }, *p = coal_settings; - u32 scale; - int i; - u16 w; + u32 scale, c_us, c_fr; + u16 intrmit; if (rtl_is_8125(tp)) return -EOPNOTSUPP; @@ -1838,24 +1836,20 @@ static int rtl_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) scale = ci->scale_nsecs[tp->cp_cmd & INTT_MASK]; - /* read IntrMitigate and adjust according to scale */ - for (w = RTL_R16(tp, IntrMitigate); w; w >>= RTL_COALESCE_SHIFT, p++) { - *p->max_frames = (w & RTL_COALESCE_MASK) << 2; - w >>= RTL_COALESCE_SHIFT; - *p->usecs = w & RTL_COALESCE_MASK; - } + intrmit = RTL_R16(tp, IntrMitigate); - for (i = 0; i < 2; i++) { - p = coal_settings + i; - *p->usecs = (*p->usecs * scale) / 1000; + c_us = FIELD_GET(RTL_COALESCE_TX_USECS, intrmit); + ec->tx_coalesce_usecs = DIV_ROUND_UP(c_us * scale, 1000); - /* - * ethtool_coalesce says it is illegal to set both usecs and - * max_frames to 0. - */ - if (!*p->usecs && !*p->max_frames) - *p->max_frames = 1; - } + c_fr = FIELD_GET(RTL_COALESCE_TX_FRAMES, intrmit); + /* ethtool_coalesce states usecs and max_frames must not both be 0 */ + ec->tx_max_coalesced_frames = (c_us || c_fr) ? c_fr * 4 : 1; + + c_us = FIELD_GET(RTL_COALESCE_RX_USECS, intrmit); + ec->rx_coalesce_usecs = DIV_ROUND_UP(c_us * scale, 1000); + + c_fr = FIELD_GET(RTL_COALESCE_RX_FRAMES, intrmit); + ec->rx_max_coalesced_frames = (c_us || c_fr) ? c_fr * 4 : 1; return 0; } -- cgit v1.2.3 From cb9d97de05646de69b997da0137b94e00cba7f99 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 30 Apr 2020 21:57:32 +0200 Subject: r8169: improve rtl_coalesce_choose_scale The time limit provided by userspace is multiplied with 1000, what could result in an overflow. Therefore change the time limit parameter unit from ns to us, and avoid the problematic operation. If there's no matching scale because provided time limit is too big, return ERANGE instead of EINVAL to provide a hint to the user what's wrong. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_main.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index a36a48f713fa..6c17c234bc06 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -1854,8 +1854,8 @@ static int rtl_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) return 0; } -/* choose appropriate scale factor and CPlusCmd[0:1] for (speed, nsec) */ -static int rtl_coalesce_choose_scale(struct rtl8169_private *tp, u32 nsec, +/* choose appropriate scale factor and CPlusCmd[0:1] for (speed, usec) */ +static int rtl_coalesce_choose_scale(struct rtl8169_private *tp, u32 usec, u16 *cp01) { const struct rtl_coalesce_info *ci; @@ -1866,13 +1866,13 @@ static int rtl_coalesce_choose_scale(struct rtl8169_private *tp, u32 nsec, return PTR_ERR(ci); for (i = 0; i < 4; i++) { - if (nsec <= ci->scale_nsecs[i] * RTL_COALESCE_T_MAX) { + if (usec <= ci->scale_nsecs[i] * RTL_COALESCE_T_MAX / 1000U) { *cp01 = i; return ci->scale_nsecs[i]; } } - return -EINVAL; + return -ERANGE; } static int rtl_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) @@ -1886,13 +1886,14 @@ static int rtl_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) { ec->tx_max_coalesced_frames, ec->tx_coalesce_usecs } }, *p = coal_settings; u16 w = 0, cp01 = 0; + u32 coal_usec_max; int scale, i; if (rtl_is_8125(tp)) return -EOPNOTSUPP; - scale = rtl_coalesce_choose_scale(tp, - max(p[0].usecs, p[1].usecs) * 1000, &cp01); + coal_usec_max = max(ec->rx_coalesce_usecs, ec->tx_coalesce_usecs); + scale = rtl_coalesce_choose_scale(tp, coal_usec_max, &cp01); if (scale < 0) return scale; -- cgit v1.2.3 From bdd2be3adb7d139a598f2277af7fa625fc399af1 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 30 Apr 2020 21:58:06 +0200 Subject: r8169: improve interrupt coalescing parameter handling The chip supports only frame limits 0, 4, 8, .. 60 internally. Returning EINVAL for all val % 4 != 0 seems to be a little bit too unfriendly to the user. Therefore round up the frame limit to the next supported value. In addition round up the time limit, else a very low limit could be rounded down to 0, and interpreted as "ignore value" by the chip. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_main.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 6c17c234bc06..a81d46abe3c2 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -1909,21 +1909,21 @@ static int rtl_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) * - then user does `ethtool -C eth0 rx-usecs 100` * * since ethtool sends to kernel whole ethtool_coalesce - * settings, if we do not handle rx_usecs=!0, rx_frames=1 - * we'll reject it below in `frames % 4 != 0`. + * settings, if we want to ignore rx_frames then it has + * to be set to 0. */ if (p->frames == 1) { p->frames = 0; } - units = p->usecs * 1000 / scale; - if (p->frames > RTL_COALESCE_FRAME_MAX || p->frames % 4) - return -EINVAL; + units = DIV_ROUND_UP(p->usecs * 1000, scale); + if (p->frames > RTL_COALESCE_FRAME_MAX) + return -ERANGE; w <<= RTL_COALESCE_SHIFT; w |= units; w <<= RTL_COALESCE_SHIFT; - w |= p->frames >> 2; + w |= DIV_ROUND_UP(p->frames, 4); } rtl_lock_work(tp); -- cgit v1.2.3 From 2b3e48b66516602d7d63142cda84b554f908eb54 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 30 Apr 2020 21:58:47 +0200 Subject: r8169: improve rtl_set_coalesce Use FIELD_PREP() to make the code better readable, and avoid the loop. No functional change intended. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_main.c | 70 +++++++++++++------------------ 1 file changed, 30 insertions(+), 40 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index a81d46abe3c2..4fe8b1d35b69 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -235,10 +235,8 @@ enum rtl_registers { #define RTL_COALESCE_RX_USECS GENMASK(7, 4) #define RTL_COALESCE_RX_FRAMES GENMASK(3, 0) -#define RTL_COALESCE_MASK 0x0f -#define RTL_COALESCE_SHIFT 4 -#define RTL_COALESCE_T_MAX (RTL_COALESCE_MASK) -#define RTL_COALESCE_FRAME_MAX (RTL_COALESCE_MASK << 2) +#define RTL_COALESCE_T_MAX 0x0fU +#define RTL_COALESCE_FRAME_MAX (RTL_COALESCE_T_MAX * 4) RxDescAddrLow = 0xe4, RxDescAddrHigh = 0xe8, @@ -1878,57 +1876,49 @@ static int rtl_coalesce_choose_scale(struct rtl8169_private *tp, u32 usec, static int rtl_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) { struct rtl8169_private *tp = netdev_priv(dev); - struct { - u32 frames; - u32 usecs; - } coal_settings [] = { - { ec->rx_max_coalesced_frames, ec->rx_coalesce_usecs }, - { ec->tx_max_coalesced_frames, ec->tx_coalesce_usecs } - }, *p = coal_settings; + u32 tx_fr = ec->tx_max_coalesced_frames; + u32 rx_fr = ec->rx_max_coalesced_frames; + u32 coal_usec_max, units; u16 w = 0, cp01 = 0; - u32 coal_usec_max; - int scale, i; + int scale; if (rtl_is_8125(tp)) return -EOPNOTSUPP; + if (rx_fr > RTL_COALESCE_FRAME_MAX || tx_fr > RTL_COALESCE_FRAME_MAX) + return -ERANGE; + coal_usec_max = max(ec->rx_coalesce_usecs, ec->tx_coalesce_usecs); scale = rtl_coalesce_choose_scale(tp, coal_usec_max, &cp01); if (scale < 0) return scale; - for (i = 0; i < 2; i++, p++) { - u32 units; - - /* - * accept max_frames=1 we returned in rtl_get_coalesce. - * accept it not only when usecs=0 because of e.g. the following scenario: - * - * - both rx_usecs=0 & rx_frames=0 in hardware (no delay on RX) - * - rtl_get_coalesce returns rx_usecs=0, rx_frames=1 - * - then user does `ethtool -C eth0 rx-usecs 100` - * - * since ethtool sends to kernel whole ethtool_coalesce - * settings, if we want to ignore rx_frames then it has - * to be set to 0. - */ - if (p->frames == 1) { - p->frames = 0; - } + /* Accept max_frames=1 we returned in rtl_get_coalesce. Accept it + * not only when usecs=0 because of e.g. the following scenario: + * + * - both rx_usecs=0 & rx_frames=0 in hardware (no delay on RX) + * - rtl_get_coalesce returns rx_usecs=0, rx_frames=1 + * - then user does `ethtool -C eth0 rx-usecs 100` + * + * Since ethtool sends to kernel whole ethtool_coalesce settings, + * if we want to ignore rx_frames then it has to be set to 0. + */ + if (rx_fr == 1) + rx_fr = 0; + if (tx_fr == 1) + tx_fr = 0; - units = DIV_ROUND_UP(p->usecs * 1000, scale); - if (p->frames > RTL_COALESCE_FRAME_MAX) - return -ERANGE; + w |= FIELD_PREP(RTL_COALESCE_TX_FRAMES, DIV_ROUND_UP(tx_fr, 4)); + w |= FIELD_PREP(RTL_COALESCE_RX_FRAMES, DIV_ROUND_UP(rx_fr, 4)); - w <<= RTL_COALESCE_SHIFT; - w |= units; - w <<= RTL_COALESCE_SHIFT; - w |= DIV_ROUND_UP(p->frames, 4); - } + units = DIV_ROUND_UP(ec->tx_coalesce_usecs * 1000U, scale); + w |= FIELD_PREP(RTL_COALESCE_TX_USECS, units); + units = DIV_ROUND_UP(ec->rx_coalesce_usecs * 1000U, scale); + w |= FIELD_PREP(RTL_COALESCE_RX_USECS, units); rtl_lock_work(tp); - RTL_W16(tp, IntrMitigate, swab16(w)); + RTL_W16(tp, IntrMitigate, w); tp->cp_cmd = (tp->cp_cmd & ~INTT_MASK) | cp01; RTL_W16(tp, CPlusCmd, tp->cp_cmd); -- cgit v1.2.3 From 81496b72e9ba1999d4ed7bb7fa407a1edef020a4 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 30 Apr 2020 21:59:48 +0200 Subject: r8169: add check for invalid parameter combination in rtl_set_coalesce Realtek provided information about a HW constraint that time limit must not be set to 0 if the frame limit is >0. Add a check for this and reject invalid parameter combinations. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 4fe8b1d35b69..aa3e63e031da 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -1908,6 +1908,11 @@ static int rtl_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) if (tx_fr == 1) tx_fr = 0; + /* HW requires time limit to be set if frame limit is set */ + if ((tx_fr && !ec->tx_coalesce_usecs) || + (rx_fr && !ec->rx_coalesce_usecs)) + return -EINVAL; + w |= FIELD_PREP(RTL_COALESCE_TX_FRAMES, DIV_ROUND_UP(tx_fr, 4)); w |= FIELD_PREP(RTL_COALESCE_RX_FRAMES, DIV_ROUND_UP(rx_fr, 4)); -- cgit v1.2.3