From: Chih Kai Hsu <hsu.chih.kai@realtek.com>
To: <davem@davemloft.net>, <kuba@kernel.org>
Cc: <netdev@vger.kernel.org>, <nic_swsd@realtek.com>,
<linux-kernel@vger.kernel.org>, <linux-usb@vger.kernel.org>,
<edumazet@google.com>, <bjorn@mork.no>, <pabeni@redhat.com>,
<hsu.chih.kai@realtek.com>, <andrew+netdev@lunn.ch>,
<mail@birger-koblitz.de>
Subject: [PATCH net-next v8 04/11] r8152: fix flow control for RTL8156/RTL8156B/RTL8157/RTL8159
Date: Tue, 10 Nov 2026 11:24:09 +0800 [thread overview]
Message-ID: <20261110032416.16968-5-nic_swsd@realtek.com> (raw)
In-Reply-To: <20261110032416.16968-1-nic_swsd@realtek.com>
The flow-control setup that limits pause frames was incomplete or
missing on several chips:
- RTL8156A (VER_10/11): r8156_init() skipped them, so the FC timer and
FLOW_CTRL_PATCH_OPT setup that the FC_PATCH_TASK toggle in
rtl8156_enable() depends on was never done.
- RTL8157/RTL8159 (VER_16/17): no limit on the number of pause packets
was programmed, so they could keep sending pause frames
indefinitely.
Collect the per-family sequence into rtl_fc_pause_pkt_en() and call it
for all of them.
- VER_10/11: the FC timer + FLOW_CTRL_PATCH_OPT sequence that
RTL8153B (VER_09) already runs from its pre_fw/post_fw hooks,
applied directly instead.
- VER_12/13/15: the sequence r8156_init() already ran, moved here
unchanged.
- VER_16/17: limit pause packets with the new PLA_PAUSE_LIMIT register
instead of the FW patch. The datasheet gives a fixed count per link
speed, reproduced here by a log2-ratio computation. Because the
count follows the negotiated speed, this family is called from
rtl8156_enable() rather than from init.
The speed decode covers every rate the driver advertises. The
hardware can also report 500 and 1250 Mbit/s, which the driver does
not advertise; if the PHY still reports such a rate, pause limiting
is disarmed rather than programmed from a guessed speed.
In r8156_init(), split AUTO_SPEEDUP clearing from the flow-control FW
patch; it still applies to RTL8156B only.
Fixes: 195aae321c82 ("r8152: support new chips")
Fixes: fd3c7d080df5 ("r8152: Add support for the RTL8157 hardware")
Fixes: ad2a55b63b41 ("r8152: Add support for the RTL8159 chip")
Signed-off-by: Chih Kai Hsu <hsu.chih.kai@realtek.com>
---
drivers/net/usb/r8152.c | 126 +++++++++++++++++++++++++++++++++++-----
1 file changed, 111 insertions(+), 15 deletions(-)
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 1517753f843ef..6f55aed4709e1 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -87,6 +87,7 @@
#define PLA_MTPS 0xe615
#define PLA_TXFIFO_CTRL 0xe618
#define PLA_TXFIFO_FULL 0xe61a
+#define PLA_PAUSE_LIMIT 0xe61e
#define PLA_RSTTALLY 0xe800
#define PLA_CR 0xe813
#define PLA_CRWECR 0xe81c
@@ -293,6 +294,10 @@
#define MTPS_JUMBO (12 * 1024 / 64)
#define MTPS_DEFAULT (6 * 1024 / 64)
+/* PLA_PAUSE_LIMIT */
+#define PAUSE_LIMIT_EN BIT(3)
+#define PAUSE_LIMIT_MASK 0xf0
+
/* PLA_RSTTALLY */
#define TALLY_RESET 0x0001
@@ -5961,6 +5966,103 @@ static void r8152b_enter_oob(struct r8152 *tp)
RCR_APM | RCR_AM | RCR_AB);
}
+static void rtl_fc_pause_pkt_en(struct r8152 *tp, u16 speed)
+{
+ int log2_ratio, ratio;
+ u16 num_pause_pkts;
+ u32 ocp_data;
+
+ switch (tp->version) {
+ case RTL_VER_10:
+ case RTL_VER_11:
+ ocp_write_word(tp, MCU_TYPE_USB, USB_FC_TIMER,
+ CTRL_TIMER_EN | (1000 / 8));
+
+ ocp_word_set_bits(tp, MCU_TYPE_USB, USB_FW_CTRL,
+ FLOW_CTRL_PATCH_OPT);
+
+ ocp_word_set_bits(tp, MCU_TYPE_USB, USB_FW_TASK, FC_PATCH_TASK);
+ break;
+ case RTL_VER_12:
+ case RTL_VER_13:
+ case RTL_VER_15:
+ ocp_word_clr_bits(tp, MCU_TYPE_PLA, PLA_RCR, SLOT_EN);
+
+ ocp_word_set_bits(tp, MCU_TYPE_PLA, PLA_CPCR, FLOW_CTRL_EN);
+
+ /* enable fc timer and set timer to 600 ms. */
+ ocp_write_word(tp, MCU_TYPE_USB, USB_FC_TIMER,
+ CTRL_TIMER_EN | (600 / 8));
+
+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_POL_GPIO_CTRL);
+ if (!(ocp_data & DACK_DET_EN))
+ ocp_word_set_bits(tp, MCU_TYPE_USB, USB_FW_CTRL,
+ FLOW_CTRL_PATCH_2);
+
+ ocp_word_set_bits(tp, MCU_TYPE_USB, USB_FW_TASK, FC_PATCH_TASK);
+ break;
+ case RTL_VER_16:
+ case RTL_VER_17:
+ ocp_word_clr_bits(tp, MCU_TYPE_PLA, PLA_RCR, SLOT_EN);
+
+ num_pause_pkts = 0xa;
+ ratio = 10000;
+
+ if (speed & _10bps) {
+ ratio /= 10;
+ } else if (speed & _100bps) {
+ ratio /= 100;
+ } else if (speed & _1000bps) {
+ ratio /= 1000;
+ } else if (speed & _2500bps) {
+ ratio /= 2500;
+ } else if (speed & _5000bps) {
+ ratio /= 5000;
+ } else if (speed & _10000bps) {
+ ratio /= 10000;
+ } else {
+ /* No rate bit is set, e.g. a 500 or 1250 Mbit/s
+ * sub-rate, which the driver does not advertise.
+ * Disarm the limit.
+ */
+ dev_err(&tp->intf->dev, "Unknown link speed\n");
+ ocp_word_clr_bits(tp, MCU_TYPE_PLA, PLA_PAUSE_LIMIT,
+ PAUSE_LIMIT_EN);
+ break;
+ }
+
+ log2_ratio = ilog2(ratio);
+ num_pause_pkts -= log2_ratio;
+
+ /* Round ratio up to the next power of two if it is
+ * more than halfway there. Floating-point is avoided
+ * by rewriting ratio > 1.5 * 2^log2_ratio as
+ * 2 * ratio > 3 * 2^log2_ratio.
+ */
+ if (2 * ratio > 3 * (1 << log2_ratio))
+ num_pause_pkts--;
+
+ /* At most 2^num_pause_pkts pause packets would be sent.
+ *
+ * 10 Mbit/s -> 2^0
+ * 100 Mbit/s -> 2^3
+ * 1 Gbit/s -> 2^7
+ * 2.5 Gbit/s -> 2^8
+ * 5 Gbit/s -> 2^9
+ * 10 Gbit/s -> 2^10
+ */
+ ocp_word_w0w1(tp, MCU_TYPE_PLA, PLA_PAUSE_LIMIT,
+ PAUSE_LIMIT_MASK | PAUSE_LIMIT_EN,
+ num_pause_pkts << 4);
+
+ ocp_word_set_bits(tp, MCU_TYPE_PLA, PLA_PAUSE_LIMIT,
+ PAUSE_LIMIT_EN);
+ break;
+ default:
+ break;
+ }
+}
+
static int r8153_pre_firmware_1(struct r8152 *tp)
{
int i;
@@ -6404,6 +6506,10 @@ static int rtl8156_enable(struct r8152 *tp)
r8153_set_rx_early_size(tp);
speed = rtl8152_get_speed(tp);
+
+ if (tp->version >= RTL_VER_16)
+ rtl_fc_pause_pkt_en(tp, speed);
+
rtl_set_ifg(tp, speed);
if (tp->version >= RTL_VER_16)
@@ -8490,22 +8596,12 @@ static void r8156_init(struct r8152 *tp)
usb_enable_lpm(tp->udev);
- if (tp->version >= RTL_VER_12 && tp->version <= RTL_VER_15) {
- ocp_word_clr_bits(tp, MCU_TYPE_PLA, PLA_RCR, SLOT_EN);
-
- ocp_word_set_bits(tp, MCU_TYPE_PLA, PLA_CPCR, FLOW_CTRL_EN);
-
- /* enable fc timer and set timer to 600 ms. */
- ocp_write_word(tp, MCU_TYPE_USB, USB_FC_TIMER, CTRL_TIMER_EN | (600 / 8));
-
- ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_CTRL);
- if (!(ocp_read_word(tp, MCU_TYPE_PLA, PLA_POL_GPIO_CTRL) & DACK_DET_EN))
- ocp_data |= FLOW_CTRL_PATCH_2;
- ocp_data &= ~AUTO_SPEEDUP;
- ocp_write_word(tp, MCU_TYPE_USB, USB_FW_CTRL, ocp_data);
+ if (tp->version < RTL_VER_16)
+ rtl_fc_pause_pkt_en(tp, 0);
- ocp_word_set_bits(tp, MCU_TYPE_USB, USB_FW_TASK, FC_PATCH_TASK);
- }
+ if (tp->version >= RTL_VER_12 && tp->version <= RTL_VER_15)
+ /* Disable Auto Speed up */
+ ocp_word_clr_bits(tp, MCU_TYPE_USB, USB_FW_CTRL, AUTO_SPEEDUP);
r8156_mac_clk_spd(tp, true);
--
2.34.1
next prev parent reply other threads:[~2026-11-10 3:25 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-10 3:24 [PATCH net-next v8 00/11] r8152: refactor and extend RTL8157/8159 support Chih Kai Hsu
2026-11-10 3:24 ` [PATCH net-next v8 01/11] r8152: fix RTL8156/RTL8156B/RTL8157/RTL8159 up and down settings Chih Kai Hsu
2026-11-10 3:24 ` [PATCH net-next v8 02/11] r8152: add rtl8157_unload() for RTL8157 and RTL8159 Chih Kai Hsu
2026-11-10 3:24 ` [PATCH net-next v8 03/11] r8152: add rtl8157_change_mtu() " Chih Kai Hsu
2026-11-10 3:24 ` Chih Kai Hsu [this message]
2026-11-10 3:24 ` [PATCH net-next v8 05/11] r8152: split r8156_init by generation and factor out wait_autoload_done Chih Kai Hsu
2026-11-10 3:24 ` [PATCH net-next v8 06/11] r8152: add new init writes for RTL8156/8156B/8157/8159 Chih Kai Hsu
2026-11-10 3:24 ` [PATCH net-next v8 07/11] r8152: split RTL_VER_17 into QFN68 and QFN100 package variants Chih Kai Hsu
2026-11-10 3:24 ` [PATCH net-next v8 08/11] r8152: split rtl8156_enable/up/down into per-generation functions Chih Kai Hsu
2026-11-10 3:24 ` [PATCH net-next v8 09/11] r8152: split r8157_hw_phy_cfg into RTL8157 and RTL8159 variants Chih Kai Hsu
2026-11-10 3:24 ` [PATCH net-next v8 10/11] r8152: add TGPHY register access for RTL8157 and RTL8159 Chih Kai Hsu
2026-11-10 3:24 ` [PATCH net-next v8 11/11] r8152: enable UPS for RTL8157 and RTL8159 QFN68 Chih Kai Hsu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261110032416.16968-5-nic_swsd@realtek.com \
--to=hsu.chih.kai@realtek.com \
--cc=andrew+netdev@lunn.ch \
--cc=bjorn@mork.no \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=mail@birger-koblitz.de \
--cc=netdev@vger.kernel.org \
--cc=nic_swsd@realtek.com \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®