[PATCH net-next 7/8] r8152: support rtl_fc_pause_pkt_en()

From: Chih Kai Hsu

Date: Wed Sep 02 2026 - 05:16:11 EST


Refactor the flow control patch as the function rtl_fc_pause_pkt_en().
Moreover, support flow control patch for RTL8156, RTL8157 and RTL8159.

Signed-off-by: Chih Kai Hsu <hsu.chih.kai@xxxxxxxxxxx>
---
drivers/net/usb/r8152.c | 112 ++++++++++++++++++++++++++++++++++------
1 file changed, 97 insertions(+), 15 deletions(-)

diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index b4c2cef0b9092..b809317de74f7 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -89,6 +89,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
@@ -301,6 +302,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

@@ -6095,6 +6100,93 @@ 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_QFN68:
+ case RTL_VER_17_QFN100:
+ ocp_word_clr_bits(tp, MCU_TYPE_PLA, PLA_RCR, SLOT_EN);
+
+ num_pause_pkts = 0xa;
+ ratio = 10000;
+
+ if (!(speed & LINK_STATUS)) {
+ dev_dbg(&tp->intf->dev, "No link\n");
+ goto no_link;
+ } else 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 {
+ dev_err(&tp->intf->dev, "Unknown link speed\n");
+ goto no_link;
+ }
+
+ log2_ratio = ilog2(ratio);
+ num_pause_pkts -= log2_ratio;
+
+ /* Round up if ratio is more than halfway to the next power of 2.
+ * 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--;
+
+no_link:
+ 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;
@@ -6626,6 +6718,8 @@ static int rtl8157_enable(struct r8152 *tp)
r8153_set_rx_early_size(tp);

speed = rtl8152_get_speed(tp);
+ rtl_fc_pause_pkt_en(tp, speed);
+
rtl_set_ifg(tp, speed);

return rtl_enable(tp);
@@ -8792,6 +8886,8 @@ static void r8156_init(struct r8152 *tp)

usb_enable_lpm(tp->udev);

+ rtl_fc_pause_pkt_en(tp, 0);
+
r8156_mac_clk_spd(tp, true);

ocp_word_clr_bits(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3,
@@ -8828,7 +8924,6 @@ static void r8156b_u2phy_backup(struct r8152 *tp)

static void r8156b_init(struct r8152 *tp)
{
- u32 ocp_data;
u16 data;
int i;

@@ -8901,20 +8996,7 @@ static void r8156b_init(struct r8152 *tp)

usb_enable_lpm(tp->udev);

- 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);
+ rtl_fc_pause_pkt_en(tp, 0);

r8156_mac_clk_spd(tp, true);

--
2.34.1