* [PATCH net-next v8 01/11] r8152: fix RTL8156/RTL8156B/RTL8157/RTL8159 up and down settings
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 ` 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
` (10 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Chih Kai Hsu @ 2026-11-10 3:24 UTC (permalink / raw)
To: davem, kuba
Cc: netdev, nic_swsd, linux-kernel, linux-usb, edumazet, bjorn,
pabeni, hsu.chih.kai, andrew+netdev, mail
Several settings the datasheet requires for these chips were either
missing or gated on the wrong version range in the shared
rtl8156_up()/rtl8156_down():
- PLA_RCR1 BIT(3) must be cleared on up for all of them. It was
cleared only for RTL_VER_16 and later, so RTL8156/RTL8156B never
reached it.
- USB_SPEED_OPTION's RG_PWRDN_EN and ALL_SPEED_OFF must be cleared on
up for RTL8157/RTL8159 as well. The "version < RTL_VER_16" check
excluded precisely the chips that need it.
- Clear_SDR must be enabled on up: USB 0xd3ca BIT(15) on RTL8156B
(VER_13/15), and USB 0xd378 BIT(7) set plus USB 0xcd06 BIT(15)
cleared on RTL8157/RTL8159.
- Entering OOB needs PLA_BDC_CR's ALDPS_PROXY_MODE and PLA_OOB_CTRL's
DIS_MCU_CLROOB. Only r8152b_enter_oob() and r8153_enter_oob() set
them; the RTL8156 family down path set NOW_IS_OOB alone.
- RTL8157/RTL8159 OOB RX settings are PLA_RMS 1526 and PLA_MTPS 10K,
not the 1522 and 6K they inherited.
- PLA_MCU_SPDWN_EN is not used by RTL8157/RTL8159, so stop managing
it on up/down for them.
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 | 52 ++++++++++++++++++++++++++++++++---------
1 file changed, 41 insertions(+), 11 deletions(-)
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 4815235e8e730..d00cc911ae135 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -6820,8 +6820,7 @@ static void rtl8156_up(struct r8152 *tp)
ocp_byte_clr_bits(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, NOW_IS_OOB);
- if (tp->version >= RTL_VER_16)
- ocp_word_clr_bits(tp, MCU_TYPE_PLA, PLA_RCR1, BIT(3));
+ ocp_word_clr_bits(tp, MCU_TYPE_PLA, PLA_RCR1, BIT(3));
ocp_word_clr_bits(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, MCU_BORW_EN);
@@ -6843,11 +6842,12 @@ static void rtl8156_up(struct r8152 *tp)
ocp_word_w0w1(tp, MCU_TYPE_PLA, PLA_RXFIFO_FULL, RXFIFO_FULL_MASK,
0x08);
- ocp_word_clr_bits(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, PLA_MCU_SPDWN_EN);
-
if (tp->version < RTL_VER_16)
- ocp_word_clr_bits(tp, MCU_TYPE_USB, USB_SPEED_OPTION,
- RG_PWRDN_EN | ALL_SPEED_OFF);
+ ocp_word_clr_bits(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3,
+ PLA_MCU_SPDWN_EN);
+
+ ocp_word_clr_bits(tp, MCU_TYPE_USB, USB_SPEED_OPTION,
+ RG_PWRDN_EN | ALL_SPEED_OFF);
ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, 0x00600400);
@@ -6860,6 +6860,23 @@ static void rtl8156_up(struct r8152 *tp)
if (tp->version < RTL_VER_16)
r8153_u2p3en(tp, true);
+ switch (tp->version) {
+ case RTL_VER_13:
+ case RTL_VER_15:
+ /* Enable Clear_SDR */
+ ocp_word_set_bits(tp, MCU_TYPE_USB, 0xd3ca, BIT(15));
+ break;
+ case RTL_VER_16:
+ case RTL_VER_17:
+ /* Enable Clear_SDR */
+ ocp_byte_set_bits(tp, MCU_TYPE_USB, 0xd378, BIT(7));
+ /* Clear SDR bit */
+ ocp_word_clr_bits(tp, MCU_TYPE_USB, 0xcd06, BIT(15));
+ break;
+ default:
+ break;
+ }
+
if (tp->version < RTL_VER_16 && tp->udev->speed >= USB_SPEED_SUPER)
r8153b_u1u2en(tp, true);
}
@@ -6871,8 +6888,9 @@ static void rtl8156_down(struct r8152 *tp)
return;
}
- ocp_word_set_bits(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3,
- PLA_MCU_SPDWN_EN);
+ if (tp->version < RTL_VER_16)
+ ocp_word_set_bits(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3,
+ PLA_MCU_SPDWN_EN);
r8153b_u1u2en(tp, false);
if (tp->version < RTL_VER_16) {
@@ -6891,8 +6909,17 @@ static void rtl8156_down(struct r8152 *tp)
rtl_disable(tp);
rtl_reset_bmu(tp);
- ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, 1522);
- ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, MTPS_DEFAULT);
+ switch (tp->version) {
+ case RTL_VER_16:
+ case RTL_VER_17:
+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, 1526);
+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, 10 * 1024 / 64);
+ break;
+ default:
+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, 1522);
+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, MTPS_DEFAULT);
+ break;
+ }
/* Clear teredo wake event. bit[15:8] is the teredo wakeup
* type. Set it to zero. bits[7:0] are the W1C bits about
@@ -6900,7 +6927,10 @@ static void rtl8156_down(struct r8152 *tp)
*/
ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_WAKE_BASE, 0x00ff);
- ocp_byte_set_bits(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, NOW_IS_OOB);
+ ocp_word_set_bits(tp, MCU_TYPE_PLA, PLA_BDC_CR, ALDPS_PROXY_MODE);
+
+ ocp_byte_set_bits(tp, MCU_TYPE_PLA, PLA_OOB_CTRL,
+ NOW_IS_OOB | DIS_MCU_CLROOB);
ocp_word_set_bits(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, MCU_BORW_EN);
--
2.34.1
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH net-next v8 02/11] r8152: add rtl8157_unload() for RTL8157 and RTL8159
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 ` Chih Kai Hsu
2026-11-10 3:24 ` [PATCH net-next v8 03/11] r8152: add rtl8157_change_mtu() " Chih Kai Hsu
` (9 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Chih Kai Hsu @ 2026-11-10 3:24 UTC (permalink / raw)
To: davem, kuba
Cc: netdev, nic_swsd, linux-kernel, linux-usb, edumazet, bjorn,
pabeni, hsu.chih.kai, andrew+netdev, mail
RTL8157 and RTL8159 used rtl8153_unload(), which disables power cut
with r8153_power_cut_en(). Per the datasheet they need
r8157_power_cut_en(), which r8156_init() already calls for them.
Add rtl8157_unload() for them, and move the Interrupt Mitigation
disable that rtl8153_unload() gated on "version >= RTL_VER_16" into
it unconditionally.
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 | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index d00cc911ae135..bb4106f238a3a 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -9696,11 +9696,6 @@ static void rtl8153_unload(struct r8152 *tp)
return;
r8153_power_cut_en(tp, false);
-
- if (tp->version >= RTL_VER_16) {
- /* Disable Interrupt Mitigation */
- ocp_byte_clr_bits(tp, MCU_TYPE_USB, 0xcf04, BIT(0) | BIT(1) | BIT(2) | BIT(7));
- }
}
static void rtl8153b_unload(struct r8152 *tp)
@@ -9711,6 +9706,16 @@ static void rtl8153b_unload(struct r8152 *tp)
r8153b_power_cut_en(tp, false);
}
+static void rtl8157_unload(struct r8152 *tp)
+{
+ if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
+ return;
+
+ r8157_power_cut_en(tp, false);
+ ocp_byte_clr_bits(tp, MCU_TYPE_USB, 0xcf04,
+ BIT(0) | BIT(1) | BIT(2) | BIT(7));
+}
+
static int r8152_desc_init(struct r8152 *tp)
{
tp->rx_desc.size = sizeof(struct rx_desc);
@@ -9889,7 +9894,7 @@ static int rtl_ops_init(struct r8152 *tp)
ops->disable = rtl8153_disable;
ops->up = rtl8156_up;
ops->down = rtl8156_down;
- ops->unload = rtl8153_unload;
+ ops->unload = rtl8157_unload;
ops->eee_get = r8153_get_eee;
ops->eee_set = r8152_set_eee;
ops->in_nway = rtl8153_in_nway;
@@ -9911,7 +9916,7 @@ static int rtl_ops_init(struct r8152 *tp)
ops->disable = rtl8153_disable;
ops->up = rtl8156_up;
ops->down = rtl8156_down;
- ops->unload = rtl8153_unload;
+ ops->unload = rtl8157_unload;
ops->eee_get = r8153_get_eee;
ops->eee_set = r8152_set_eee;
ops->in_nway = rtl8153_in_nway;
--
2.34.1
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH net-next v8 03/11] r8152: add rtl8157_change_mtu() for RTL8157 and RTL8159
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 ` Chih Kai Hsu
2026-11-10 3:24 ` [PATCH net-next v8 04/11] r8152: fix flow control for RTL8156/RTL8156B/RTL8157/RTL8159 Chih Kai Hsu
` (8 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Chih Kai Hsu @ 2026-11-10 3:24 UTC (permalink / raw)
To: davem, kuba
Cc: netdev, nic_swsd, linux-kernel, linux-usb, edumazet, bjorn,
pabeni, hsu.chih.kai, andrew+netdev, mail
RTL8157 and RTL8159 used rtl8156_change_mtu(), which programs a fixed
MTPS_JUMBO. Per the datasheet they need an MTPS scaled from the
configured MTU instead: max_pkt_size / 64, at least 10K and capped
at 0xff.
Add rtl8157_change_mtu() for them. Since rtl8156_up() is shared with
these chips, have it call tp->rtl_ops.change_mtu() instead of
rtl8156_change_mtu() directly so each chip gets its own helper.
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 | 28 +++++++++++++++++++++++++---
1 file changed, 25 insertions(+), 3 deletions(-)
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index bb4106f238a3a..1517753f843ef 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -6800,6 +6800,28 @@ static void rtl8156_change_mtu(struct r8152 *tp)
ALIGN(rx_max_size + tp->tx_desc.size, 1024) / 16);
}
+static void rtl8157_change_mtu(struct r8152 *tp)
+{
+ u32 max_pkt_size = mtu_to_size(tp->netdev->mtu);
+ u32 ocp_data;
+
+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, max_pkt_size);
+
+ /* Use at least 10K for MTPS */
+ ocp_data = max_t(u32, max_pkt_size, 10 * 1024) / 64;
+
+ /* 16 * 1024 / 64 = 0x100, so the max is 0xff for 8 bits data */
+ ocp_data = min_t(u32, ocp_data, 0xff);
+
+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, ocp_data);
+ r8156_fc_parameter(tp);
+
+ /* TX share fifo free credit full threshold */
+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, 512 / 64);
+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_TXFIFO_FULL,
+ ALIGN(max_pkt_size + tp->tx_desc.size, 1024) / 16);
+}
+
static void rtl8156_up(struct r8152 *tp)
{
if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
@@ -6826,7 +6848,7 @@ static void rtl8156_up(struct r8152 *tp)
rtl_rx_vlan_en(tp, tp->netdev->features & NETIF_F_HW_VLAN_CTAG_RX);
- rtl8156_change_mtu(tp);
+ tp->rtl_ops.change_mtu(tp);
switch (tp->version) {
case RTL_TEST_01:
@@ -9900,7 +9922,7 @@ static int rtl_ops_init(struct r8152 *tp)
ops->in_nway = rtl8153_in_nway;
ops->hw_phy_cfg = r8157_hw_phy_cfg;
ops->autosuspend_en = rtl8157_runtime_enable;
- ops->change_mtu = rtl8156_change_mtu;
+ ops->change_mtu = rtl8157_change_mtu;
tp->rx_buf_sz = 32 * 1024;
tp->support_2500full = 1;
tp->support_5000full = 1;
@@ -9922,7 +9944,7 @@ static int rtl_ops_init(struct r8152 *tp)
ops->in_nway = rtl8153_in_nway;
ops->hw_phy_cfg = r8157_hw_phy_cfg;
ops->autosuspend_en = rtl8157_runtime_enable;
- ops->change_mtu = rtl8156_change_mtu;
+ ops->change_mtu = rtl8157_change_mtu;
tp->rx_buf_sz = 48 * 1024;
tp->support_2500full = 1;
tp->support_5000full = 1;
--
2.34.1
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH net-next v8 04/11] r8152: fix flow control for RTL8156/RTL8156B/RTL8157/RTL8159
2026-11-10 3:24 [PATCH net-next v8 00/11] r8152: refactor and extend RTL8157/8159 support Chih Kai Hsu
` (2 preceding siblings ...)
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
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
` (7 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Chih Kai Hsu @ 2026-11-10 3:24 UTC (permalink / raw)
To: davem, kuba
Cc: netdev, nic_swsd, linux-kernel, linux-usb, edumazet, bjorn,
pabeni, hsu.chih.kai, andrew+netdev, mail
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
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH net-next v8 05/11] r8152: split r8156_init by generation and factor out wait_autoload_done
2026-11-10 3:24 [PATCH net-next v8 00/11] r8152: refactor and extend RTL8157/8159 support Chih Kai Hsu
` (3 preceding siblings ...)
2026-11-10 3:24 ` [PATCH net-next v8 04/11] r8152: fix flow control for RTL8156/RTL8156B/RTL8157/RTL8159 Chih Kai Hsu
@ 2026-11-10 3:24 ` 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
` (6 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Chih Kai Hsu @ 2026-11-10 3:24 UTC (permalink / raw)
To: davem, kuba
Cc: netdev, nic_swsd, linux-kernel, linux-usb, edumazet, bjorn,
pabeni, hsu.chih.kai, andrew+netdev, mail
RTL8156, RTL8156B, RTL8157 and RTL8159 shared a single r8156_init(),
gated by a dense set of tp->version range checks. That made the init
sequence hard to follow.
Split r8156_init() into two functions by chip generation:
- r8156_init (VER_10/11 and VER_12/13/15, RTL8156 and RTL8156B)
- r8157_init (VER_16/17, RTL8157 and RTL8159)
The members of each generation have near-identical sequences, so they
share a function and branch on tp->version only for the few real
differences, such as the RTL8156B-only AUTO_SPEEDUP clear or the
RTL8159-only backup-restore wait.
Also factor the repeated "poll PLA_BOOT_CTRL for AUTOLOAD_DONE" loop
into wait_autoload_done(), reusing read_poll_timeout() instead of the
500 * msleep(20) loops. r8153_init(), r8153b_init(),
r8153c_init(), r8153b_ups_en() and r8153c_ups_en() are converted to
use it too.
wait_autoload_done() only reports failure (nonzero) when
RTL8152_INACCESSIBLE is set; a plain AUTOLOAD_DONE timeout is logged
but otherwise treated as success, same as every one of the loops it
replaces, which only gave up on RTL8152_INACCESSIBLE and otherwise
fell through to the rest of the init sequence (r8153_init() and
r8153b_init() ignore even that, as before). The two
failure modes are not equivalent: once RTL8152_INACCESSIBLE is set,
generic_ocp_read()/generic_ocp_write() short-circuit to -ENODEV
without touching the device, so returning early costs nothing. A plain
timeout means the device is still reachable, so skipping the rest of
the bring-up would leave real hardware state half-configured.
No functional change intended.
Signed-off-by: Chih Kai Hsu <hsu.chih.kai@realtek.com>
---
drivers/net/usb/r8152.c | 310 +++++++++++++++++++++++-----------------
1 file changed, 180 insertions(+), 130 deletions(-)
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 6f55aed4709e1..364a0573f6cd1 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -4177,6 +4177,23 @@ static u16 r8153_phy_status(struct r8152 *tp, u16 desired)
return data;
}
+static int wait_autoload_done(struct r8152 *tp)
+{
+ u16 ocp_data;
+ int ret;
+
+ ret = read_poll_timeout(ocp_read_word, ocp_data,
+ test_bit(RTL8152_INACCESSIBLE, &tp->flags) ||
+ (ocp_data & AUTOLOAD_DONE),
+ 20000, 10 * USEC_PER_SEC, false, tp,
+ MCU_TYPE_PLA, PLA_BOOT_CTRL);
+
+ if (ret)
+ dev_err(&tp->intf->dev, "autoload done timeout\n");
+
+ return test_bit(RTL8152_INACCESSIBLE, &tp->flags) ? -ENODEV : 0;
+}
+
static void r8153b_ups_en(struct r8152 *tp, bool enable)
{
if (enable) {
@@ -4195,16 +4212,8 @@ static void r8153b_ups_en(struct r8152 *tp, bool enable)
UPS_FORCE_PWR_DOWN);
if (ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0) & PCUT_STATUS) {
- int i;
-
- for (i = 0; i < 500; i++) {
- if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
- return;
- if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) &
- AUTOLOAD_DONE)
- break;
- msleep(20);
- }
+ if (wait_autoload_done(tp))
+ return;
tp->rtl_ops.hw_phy_cfg(tp);
@@ -4232,16 +4241,8 @@ static void r8153c_ups_en(struct r8152 *tp, bool enable)
UPS_FORCE_PWR_DOWN);
if (ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0) & PCUT_STATUS) {
- int i;
-
- for (i = 0; i < 500; i++) {
- if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
- return;
- if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) &
- AUTOLOAD_DONE)
- break;
- msleep(20);
- }
+ if (wait_autoload_done(tp))
+ return;
tp->rtl_ops.hw_phy_cfg(tp);
@@ -7386,22 +7387,13 @@ static void r8152b_init(struct r8152 *tp)
static void r8153_init(struct r8152 *tp)
{
u32 ocp_data;
- int i;
if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
return;
r8153_u1u2en(tp, false);
- for (i = 0; i < 500; i++) {
- if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) &
- AUTOLOAD_DONE)
- break;
-
- msleep(20);
- if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
- break;
- }
+ wait_autoload_done(tp);
r8153_phy_status(tp, 0);
@@ -7502,22 +7494,12 @@ static void r8153_init(struct r8152 *tp)
static void r8153b_init(struct r8152 *tp)
{
- int i;
-
if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
return;
r8153b_u1u2en(tp, false);
- for (i = 0; i < 500; i++) {
- if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) &
- AUTOLOAD_DONE)
- break;
-
- msleep(20);
- if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
- break;
- }
+ wait_autoload_done(tp);
r8153_phy_status(tp, 0);
@@ -7572,8 +7554,6 @@ static void r8153b_init(struct r8152 *tp)
static void r8153c_init(struct r8152 *tp)
{
- int i;
-
if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
return;
@@ -7586,15 +7566,8 @@ static void r8153c_init(struct r8152 *tp)
ocp_word_set_bits(tp, MCU_TYPE_USB, 0xcbf0, BIT(1));
- for (i = 0; i < 500; i++) {
- if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) &
- AUTOLOAD_DONE)
- break;
-
- msleep(20);
- if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
- return;
- }
+ if (wait_autoload_done(tp))
+ return;
r8153_phy_status(tp, 0);
@@ -8491,90 +8464,63 @@ static void r8157_hw_phy_cfg(struct r8152 *tp)
set_bit(PHY_RESET, &tp->flags);
}
-static int r8159_wait_backup_restore(struct r8152 *tp)
-{
- u32 ocp_data;
-
- ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0);
- if (!(ocp_data & PCUT_STATUS))
- return 0;
-
- return poll_timeout_us(ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_GPHY_CTRL),
- ocp_data & BACKUP_RESTRORE, 200, 20000, false);
-}
-
static void r8156_init(struct r8152 *tp)
{
- u32 ocp_data;
u16 data;
- int i;
if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
return;
- if (tp->version == RTL_VER_16 || tp->version == RTL_VER_17) {
- ocp_byte_set_bits(tp, MCU_TYPE_USB, 0xcffe, BIT(3));
- ocp_byte_clr_bits(tp, MCU_TYPE_USB, 0xd3ca, BIT(0));
- }
-
ocp_byte_clr_bits(tp, MCU_TYPE_USB, USB_ECM_OP, EN_ALL_SPEED);
- if (tp->version < RTL_VER_16)
- ocp_write_word(tp, MCU_TYPE_USB, USB_SPEED_OPTION, 0);
+ ocp_write_word(tp, MCU_TYPE_USB, USB_SPEED_OPTION, 0);
ocp_word_set_bits(tp, MCU_TYPE_USB, USB_ECM_OPTION, BYPASS_MAC_RESET);
- if (tp->version >= RTL_VER_12 && tp->version <= RTL_VER_15)
+ switch (tp->version) {
+ case RTL_VER_12:
+ case RTL_VER_13:
+ case RTL_VER_15:
ocp_word_set_bits(tp, MCU_TYPE_USB, USB_U2P3_CTRL, RX_DETECT8);
+ break;
+ default:
+ break;
+ }
r8153b_u1u2en(tp, false);
switch (tp->version) {
case RTL_VER_13:
case RTL_VER_15:
- case RTL_VER_16:
- case RTL_VER_17:
r8156b_wait_loading_flash(tp);
break;
default:
break;
}
- for (i = 0; i < 500; i++) {
- if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) &
- AUTOLOAD_DONE)
- break;
-
- msleep(20);
- if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
- return;
- }
-
- if (tp->version == RTL_VER_17 && r8159_wait_backup_restore(tp)) {
- rtl_set_inaccessible(tp);
- dev_err(&tp->intf->dev, "init failed, backup-restore timed out\n");
+ if (wait_autoload_done(tp))
return;
- }
data = r8153_phy_status(tp, 0);
if (data == PHY_STAT_EXT_INIT) {
ocp_reg_clr_bits(tp, 0xa468, BIT(3) | BIT(1));
- if (tp->version >= RTL_VER_12)
+
+ switch (tp->version) {
+ case RTL_VER_12:
+ case RTL_VER_13:
+ case RTL_VER_15:
ocp_reg_clr_bits(tp, 0xa466, BIT(0));
+ break;
+ default:
+ break;
+ }
}
- data = r8152_mdio_read(tp, MII_BMCR);
- if (data & BMCR_PDOWN) {
- data &= ~BMCR_PDOWN;
- r8152_mdio_write(tp, MII_BMCR, data);
- }
+ r8152_mdio_test_and_clr_bit(tp, MII_BMCR, BMCR_PDOWN);
data = r8153_phy_status(tp, PHY_STAT_LAN_ON);
- if (tp->version >= RTL_VER_16)
- r8157_u2p3en(tp, false);
- else
- r8153_u2p3en(tp, false);
+ r8153_u2p3en(tp, false);
/* MSC timer = 0xfff * 8ms = 32760 ms */
ocp_write_word(tp, MCU_TYPE_USB, USB_MSC_TIMER, 0x0fff);
@@ -8582,11 +8528,7 @@ static void r8156_init(struct r8152 *tp)
/* U1/U2/L1 idle timer. 500 us */
ocp_write_word(tp, MCU_TYPE_USB, USB_U1U2_TIMER, 500);
- if (tp->version >= RTL_VER_16)
- r8157_power_cut_en(tp, false);
- else
- r8153b_power_cut_en(tp, false);
-
+ r8153b_power_cut_en(tp, false);
r8156_ups_en(tp, false);
r8153_queue_wake(tp, false);
rtl_runtime_suspend_enable(tp, false);
@@ -8596,48 +8538,156 @@ static void r8156_init(struct r8152 *tp)
usb_enable_lpm(tp->udev);
- if (tp->version < RTL_VER_16)
- rtl_fc_pause_pkt_en(tp, 0);
+ rtl_fc_pause_pkt_en(tp, 0);
- if (tp->version >= RTL_VER_12 && tp->version <= RTL_VER_15)
+ switch (tp->version) {
+ case RTL_VER_12:
+ case RTL_VER_13:
+ case RTL_VER_15:
/* Disable Auto Speed up */
ocp_word_clr_bits(tp, MCU_TYPE_USB, USB_FW_CTRL, AUTO_SPEEDUP);
+ break;
+ default:
+ break;
+ }
r8156_mac_clk_spd(tp, true);
- if (tp->version < RTL_VER_16)
- ocp_word_clr_bits(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, PLA_MCU_SPDWN_EN);
+ ocp_word_clr_bits(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, PLA_MCU_SPDWN_EN);
- ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS);
if (rtl8152_get_speed(tp) & LINK_STATUS)
- ocp_data |= CUR_LINK_OK;
+ ocp_word_set_bits(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS,
+ CUR_LINK_OK | POLL_LINK_CHG);
else
- ocp_data &= ~CUR_LINK_OK;
- ocp_data |= POLL_LINK_CHG;
- ocp_write_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS, ocp_data);
+ ocp_word_w0w1(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS, CUR_LINK_OK,
+ POLL_LINK_CHG);
+
+ set_bit(GREEN_ETHERNET, &tp->flags);
+
+ ocp_word_clr_bits(tp, MCU_TYPE_USB, USB_USB_CTRL,
+ RX_AGG_DISABLE | RX_ZERO_EN);
+
+ switch (tp->version) {
+ case RTL_TEST_01:
+ case RTL_VER_10:
+ case RTL_VER_11:
+ ocp_byte_set_bits(tp, MCU_TYPE_USB, USB_BMU_CONFIG, ACT_ODMA);
+ break;
+ default:
+ break;
+ }
+
+ r8156_mdio_force_mode(tp);
+ rtl_tally_reset(tp);
+
+ tp->coalesce = 15000; /* 15 us */
+}
+
+static int r8159_wait_backup_restore(struct r8152 *tp)
+{
+ u32 ocp_data;
+
+ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0);
+ if (!(ocp_data & PCUT_STATUS))
+ return 0;
+
+ return poll_timeout_us(ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_GPHY_CTRL),
+ ocp_data & BACKUP_RESTRORE, 200, 20000, false);
+}
+
+static void r8157_init(struct r8152 *tp)
+{
+ u16 data;
+
+ if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
+ return;
+
+ /* Enable SW reset */
+ ocp_byte_set_bits(tp, MCU_TYPE_USB, 0xcffe, BIT(3));
+ ocp_byte_clr_bits(tp, MCU_TYPE_USB, 0xd3ca, BIT(0));
+
+ ocp_byte_clr_bits(tp, MCU_TYPE_USB, USB_ECM_OP, EN_ALL_SPEED);
+
+ ocp_word_set_bits(tp, MCU_TYPE_USB, USB_ECM_OPTION, BYPASS_MAC_RESET);
+
+ r8153b_u1u2en(tp, false);
+
+ r8156b_wait_loading_flash(tp);
+
+ if (wait_autoload_done(tp))
+ return;
+
+ switch (tp->version) {
+ case RTL_VER_17:
+ if (r8159_wait_backup_restore(tp)) {
+ rtl_set_inaccessible(tp);
+ dev_err(&tp->intf->dev,
+ "init failed, backup-restore timed out\n");
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+
+ data = r8153_phy_status(tp, 0);
+ if (data == PHY_STAT_EXT_INIT) {
+ ocp_reg_clr_bits(tp, 0xa468, BIT(3) | BIT(1));
+ ocp_reg_clr_bits(tp, 0xa466, BIT(0));
+ }
+
+ r8152_mdio_test_and_clr_bit(tp, MII_BMCR, BMCR_PDOWN);
+
+ data = r8153_phy_status(tp, PHY_STAT_LAN_ON);
+
+ r8157_u2p3en(tp, false);
+
+ /* MSC timer = 0xfff * 8ms = 32760 ms */
+ ocp_write_word(tp, MCU_TYPE_USB, USB_MSC_TIMER, 0x0fff);
+
+ /* U1/U2/L1 idle timer. 500 us */
+ ocp_write_word(tp, MCU_TYPE_USB, USB_U1U2_TIMER, 500);
+
+ r8157_power_cut_en(tp, false);
+ r8156_ups_en(tp, false);
+ r8153_queue_wake(tp, false);
+ rtl_runtime_suspend_enable(tp, false);
+
+ if (tp->udev->speed >= USB_SPEED_SUPER)
+ r8153b_u1u2en(tp, true);
+
+ usb_enable_lpm(tp->udev);
+
+ r8156_mac_clk_spd(tp, true);
+
+ if (rtl8152_get_speed(tp) & LINK_STATUS)
+ ocp_word_set_bits(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS,
+ CUR_LINK_OK | POLL_LINK_CHG);
+ else
+ ocp_word_w0w1(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS, CUR_LINK_OK,
+ POLL_LINK_CHG);
set_bit(GREEN_ETHERNET, &tp->flags);
/* RX aggregation / 16 bytes RX descriptor
* BIT(11) is specific to RTL8159, with unknown meaning
*/
- if (tp->version == RTL_VER_17)
+ switch (tp->version) {
+ case RTL_VER_17:
ocp_word_clr_bits(tp, MCU_TYPE_USB, USB_USB_CTRL,
RX_AGG_DISABLE | RX_DESC_16B | BIT(11));
- else if (tp->version == RTL_VER_16)
- ocp_word_clr_bits(tp, MCU_TYPE_USB, USB_USB_CTRL, RX_AGG_DISABLE | RX_DESC_16B);
- else
- ocp_word_clr_bits(tp, MCU_TYPE_USB, USB_USB_CTRL, RX_AGG_DISABLE | RX_ZERO_EN);
+ break;
+ default:
+ ocp_word_clr_bits(tp, MCU_TYPE_USB, USB_USB_CTRL,
+ RX_AGG_DISABLE | RX_DESC_16B);
+ break;
+ }
- if (tp->version < RTL_VER_12)
- ocp_byte_set_bits(tp, MCU_TYPE_USB, USB_BMU_CONFIG, ACT_ODMA);
+ /* Disable Rx Zero Len */
+ rtl_bmu_clr_bits(tp, 0x2300, BIT(3));
- if (tp->version >= RTL_VER_16) {
- /* Disable Rx Zero Len */
- rtl_bmu_clr_bits(tp, 0x2300, BIT(3));
- /* TX descriptor Signature */
- ocp_byte_clr_bits(tp, MCU_TYPE_USB, 0xd4ae, BIT(1));
- }
+ /* TX descriptor Signature */
+ ocp_byte_clr_bits(tp, MCU_TYPE_USB, 0xd4ae, BIT(1));
r8156_mdio_force_mode(tp);
rtl_tally_reset(tp);
@@ -10007,7 +10057,7 @@ static int rtl_ops_init(struct r8152 *tp)
tp->eee_en = true;
tp->eee_adv = MDIO_EEE_1000T | MDIO_EEE_100TX;
tp->eee_adv2 = MDIO_EEE_2_5GT | MDIO_EEE_5GT;
- ops->init = r8156_init;
+ ops->init = r8157_init;
ops->enable = rtl8156_enable;
ops->disable = rtl8153_disable;
ops->up = rtl8156_up;
@@ -10029,7 +10079,7 @@ static int rtl_ops_init(struct r8152 *tp)
tp->eee_en = true;
tp->eee_adv = MDIO_EEE_100TX | MDIO_EEE_1000T | MDIO_EEE_10GT;
tp->eee_adv2 = MDIO_EEE_2_5GT | MDIO_EEE_5GT;
- ops->init = r8156_init;
+ ops->init = r8157_init;
ops->enable = rtl8156_enable;
ops->disable = rtl8153_disable;
ops->up = rtl8156_up;
--
2.34.1
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH net-next v8 06/11] r8152: add new init writes for RTL8156/8156B/8157/8159
2026-11-10 3:24 [PATCH net-next v8 00/11] r8152: refactor and extend RTL8157/8159 support Chih Kai Hsu
` (4 preceding siblings ...)
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 ` 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
` (5 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Chih Kai Hsu @ 2026-11-10 3:24 UTC (permalink / raw)
To: davem, kuba
Cc: netdev, nic_swsd, linux-kernel, linux-usb, edumazet, bjorn,
pabeni, hsu.chih.kai, andrew+netdev, mail
Bring the per-generation init functions in line with the vendor init
sequence by adding writes the shared r8156_init() never performed.
- Clear PREBOOT_OPTION and RMT_WAKE_EN in r8156_init() and
r8157_init().
- Add r8156b_u2phy_backup() for RTL8156B (VER_13/15).
- Clear AUTO_SPEEDUP in r8157_init().
- Disable interrupt mitigation (0xcf04) in r8157_init().
- Clear the Warm RST / Bus RST event flag (0xcd06 BIT(11)) in
r8157_init().
- Clear the FW u1u2 patch option (0xb9a6 BIT(0)) and enable the u3phy
patch backup (0xb9a2) for RTL8159 (VER_17) only.
- Clear RX_END_TRANSFER_EN (0xd406 BIT(11)) for RTL8157 (VER_16), too.
While it is set, incoming packets are buffered in the RX FIFO and
Bulk-in transfers are suspended. The bit is zero by default and
isn't used now. Clear it unconditionally for safety.
Signed-off-by: Chih Kai Hsu <hsu.chih.kai@realtek.com>
---
drivers/net/usb/r8152.c | 76 ++++++++++++++++++++++++++++++++++-------
1 file changed, 63 insertions(+), 13 deletions(-)
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 364a0573f6cd1..a1c2e1e08b161 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -78,6 +78,7 @@
#define PLA_EEE_TXTWSYS_2P5G 0xe058
#define PLA_EEEP_CR 0xe080
#define PLA_MAC_PWR_CTRL 0xe0c0
+#define PLA_RMT_WAKE 0xe0c8
#define PLA_MAC_PWR_CTRL2 0xe0ca
#define PLA_MAC_PWR_CTRL3 0xe0cc
#define PLA_MAC_PWR_CTRL4 0xe0ce
@@ -376,6 +377,9 @@
#define MCU_CLK_RATIO_MASK 0x0f0f0f0f
#define ALDPS_SPDWN_RATIO 0x0f87
+/* PLA_RMT_WAKE */
+#define RMT_WAKE_EN BIT(0)
+
/* PLA_MAC_PWR_CTRL2 */
#define EEE_SPDWN_RATIO 0x8007
#define MAC_CLK_SPDWN_EN BIT(15)
@@ -422,6 +426,7 @@
/* PLA_INDICATE_FALG */
#define UPCOMING_RUNTIME_D3 BIT(0)
+#define PREBOOT_OPTION BIT(1)
/* PLA_MACDBG_PRE and PLA_MACDBG_POST */
#define DEBUG_OE BIT(0)
@@ -547,6 +552,7 @@
#define RX_AGG_DISABLE 0x0010
#define RX_ZERO_EN 0x0080
#define RX_DESC_16B 0x0400
+#define RX_END_TRANSFER_EN BIT(11)
/* USB_U2P3_CTRL */
#define U2P3_ENABLE 0x0001
@@ -8464,6 +8470,15 @@ static void r8157_hw_phy_cfg(struct r8152 *tp)
set_bit(PHY_RESET, &tp->flags);
}
+static void r8156b_u2phy_backup(struct r8152 *tp)
+{
+ ocp_write_word(tp, MCU_TYPE_USB, 0xd3ce, 0x181b);
+ ocp_write_dword(tp, MCU_TYPE_USB, 0xd3d0, 0x616ccd99);
+ ocp_write_dword(tp, MCU_TYPE_USB, 0xd3d4, 0x08fc8101);
+ ocp_write_dword(tp, MCU_TYPE_USB, 0xd3d8, 0x159b1100);
+ ocp_write_word(tp, MCU_TYPE_USB, 0xd3dc, 0x0a00);
+}
+
static void r8156_init(struct r8152 *tp)
{
u16 data;
@@ -8528,11 +8543,24 @@ static void r8156_init(struct r8152 *tp)
/* U1/U2/L1 idle timer. 500 us */
ocp_write_word(tp, MCU_TYPE_USB, USB_U1U2_TIMER, 500);
+ switch (tp->version) {
+ case RTL_VER_13:
+ case RTL_VER_15:
+ r8156b_u2phy_backup(tp);
+ break;
+ default:
+ break;
+ }
+
r8153b_power_cut_en(tp, false);
r8156_ups_en(tp, false);
r8153_queue_wake(tp, false);
rtl_runtime_suspend_enable(tp, false);
+ ocp_byte_clr_bits(tp, MCU_TYPE_PLA, PLA_INDICATE_FALG, PREBOOT_OPTION);
+
+ ocp_byte_clr_bits(tp, MCU_TYPE_PLA, PLA_RMT_WAKE, RMT_WAKE_EN);
+
if (tp->udev->speed >= USB_SPEED_SUPER)
r8153b_u1u2en(tp, true);
@@ -8642,6 +8670,10 @@ static void r8157_init(struct r8152 *tp)
r8157_u2p3en(tp, false);
+ /* Disable Interrupt Mitigation */
+ ocp_byte_clr_bits(tp, MCU_TYPE_USB, 0xcf04,
+ BIT(0) | BIT(1) | BIT(2) | BIT(7));
+
/* MSC timer = 0xfff * 8ms = 32760 ms */
ocp_write_word(tp, MCU_TYPE_USB, USB_MSC_TIMER, 0x0fff);
@@ -8653,11 +8685,30 @@ static void r8157_init(struct r8152 *tp)
r8153_queue_wake(tp, false);
rtl_runtime_suspend_enable(tp, false);
+ ocp_byte_clr_bits(tp, MCU_TYPE_PLA, PLA_INDICATE_FALG, PREBOOT_OPTION);
+
+ ocp_byte_clr_bits(tp, MCU_TYPE_PLA, PLA_RMT_WAKE, RMT_WAKE_EN);
+
+ /* Clear Warm RST / Bus RST event flag */
+ ocp_word_clr_bits(tp, MCU_TYPE_USB, 0xcd06, BIT(11));
+
+ switch (tp->version) {
+ case RTL_VER_17:
+ /* Disable FW u1u2 patch option */
+ ocp_byte_clr_bits(tp, MCU_TYPE_USB, 0xb9a6, BIT(0));
+ break;
+ default:
+ break;
+ }
+
if (tp->udev->speed >= USB_SPEED_SUPER)
r8153b_u1u2en(tp, true);
usb_enable_lpm(tp->udev);
+ /* Disable Auto Speed up */
+ ocp_word_clr_bits(tp, MCU_TYPE_USB, USB_FW_CTRL, AUTO_SPEEDUP);
+
r8156_mac_clk_spd(tp, true);
if (rtl8152_get_speed(tp) & LINK_STATUS)
@@ -8669,19 +8720,9 @@ static void r8157_init(struct r8152 *tp)
set_bit(GREEN_ETHERNET, &tp->flags);
- /* RX aggregation / 16 bytes RX descriptor
- * BIT(11) is specific to RTL8159, with unknown meaning
- */
- switch (tp->version) {
- case RTL_VER_17:
- ocp_word_clr_bits(tp, MCU_TYPE_USB, USB_USB_CTRL,
- RX_AGG_DISABLE | RX_DESC_16B | BIT(11));
- break;
- default:
- ocp_word_clr_bits(tp, MCU_TYPE_USB, USB_USB_CTRL,
- RX_AGG_DISABLE | RX_DESC_16B);
- break;
- }
+ /* RX aggregation / 16 bytes RX descriptor / Bulk In End transfer */
+ ocp_word_clr_bits(tp, MCU_TYPE_USB, USB_USB_CTRL,
+ RX_AGG_DISABLE | RX_DESC_16B | RX_END_TRANSFER_EN);
/* Disable Rx Zero Len */
rtl_bmu_clr_bits(tp, 0x2300, BIT(3));
@@ -8689,6 +8730,15 @@ static void r8157_init(struct r8152 *tp)
/* TX descriptor Signature */
ocp_byte_clr_bits(tp, MCU_TYPE_USB, 0xd4ae, BIT(1));
+ switch (tp->version) {
+ case RTL_VER_17:
+ /* Enable u3phy patch backup */
+ ocp_write_word(tp, MCU_TYPE_USB, 0xb9a2, 0x0448);
+ break;
+ default:
+ break;
+ }
+
r8156_mdio_force_mode(tp);
rtl_tally_reset(tp);
--
2.34.1
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH net-next v8 07/11] r8152: split RTL_VER_17 into QFN68 and QFN100 package variants
2026-11-10 3:24 [PATCH net-next v8 00/11] r8152: refactor and extend RTL8157/8159 support Chih Kai Hsu
` (5 preceding siblings ...)
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 ` 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
` (4 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Chih Kai Hsu @ 2026-11-10 3:24 UTC (permalink / raw)
To: davem, kuba
Cc: netdev, nic_swsd, linux-kernel, linux-usb, edumazet, bjorn,
pabeni, hsu.chih.kai, andrew+netdev, mail
RTL8159 is sold in QFN68 and QFN100 packages, and only QFN68 needs
the u2phy backup-restore patch and enables UPS (in a later patch).
There was previously no way to tell the two apart at runtime, since
both used the same RTL_VER_17.
Split RTL_VER_17 into RTL_VER_17_QFN68 and RTL_VER_17_QFN100 and
update every switch/case on RTL_VER_17 in the driver to handle both.
Detect the package by reading the new PLA_PKG_DET register
(0xdc48, masked with PKG_MASK = 0x1e) via a new __rtl_get_pkg_det()
helper, called from __rtl_get_hw_ver() when the chip ID is 0x2020:
pkg_det value 0x1e/0x1c selects QFN68, 0x18/0x1a selects QFN100, and
any other value logs "Unknown package" and falls back to
RTL_VER_UNKNOWN.
r8157_init() gains a QFN68-only write ("Enable u2phy backup restore
patch", 0xb99c BIT(0)) that does not apply to QFN100.
Signed-off-by: Chih Kai Hsu <hsu.chih.kai@realtek.com>
---
drivers/net/usb/r8152.c | 106 ++++++++++++++++++++++++++++++++--------
1 file changed, 86 insertions(+), 20 deletions(-)
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index a1c2e1e08b161..b6f252722a5eb 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -64,6 +64,7 @@
#define PLA_MACDBG_POST 0xd38e /* RTL_VER_04 only */
#define PLA_EXTRA_STATUS 0xd398
#define PLA_GPHY_CTRL 0xd3ae
+#define PLA_PKG_DET 0xdc48
#define PLA_POL_GPIO_CTRL 0xdc6a
#define PLA_EFUSE_DATA 0xdd00
#define PLA_EFUSE_CMD 0xdd02
@@ -291,6 +292,9 @@
#define IFG_144NS BIT(9)
#define IFG_96NS (BIT(9) | BIT(8))
+/* PLA_PKG_DET */
+#define PKG_MASK 0x1e
+
/* PLA_MTPS */
#define MTPS_JUMBO (12 * 1024 / 64)
#define MTPS_DEFAULT (6 * 1024 / 64)
@@ -1258,7 +1262,8 @@ enum rtl_version {
RTL_VER_14,
RTL_VER_15,
RTL_VER_16,
- RTL_VER_17,
+ RTL_VER_17_QFN68,
+ RTL_VER_17_QFN100,
RTL_VER_MAX
};
@@ -3423,7 +3428,8 @@ static void rtl8152_nic_reset(struct r8152 *tp)
break;
case RTL_VER_16:
- case RTL_VER_17:
+ case RTL_VER_17_QFN68:
+ case RTL_VER_17_QFN100:
ocp_byte_clr_bits(tp, MCU_TYPE_PLA, PLA_CR, CR_RE | CR_TE);
break;
@@ -3463,7 +3469,7 @@ static void rtl_eee_plus_en(struct r8152 *tp, bool enable)
static void rtl_set_eee_plus(struct r8152 *tp)
{
- if (tp->version == RTL_VER_17)
+ if (tp->version == RTL_VER_17_QFN68 || tp->version == RTL_VER_17_QFN100)
return rtl_eee_plus_en(tp, false);
if (rtl8152_get_speed(tp) & _10bps)
@@ -3651,7 +3657,8 @@ static void r8153_set_rx_early_timeout(struct r8152 *tp)
case RTL_VER_13:
case RTL_VER_15:
case RTL_VER_16:
- case RTL_VER_17:
+ case RTL_VER_17_QFN68:
+ case RTL_VER_17_QFN100:
ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_TIMEOUT,
640 / 8);
ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EXTRA_AGGR_TMR,
@@ -3696,7 +3703,8 @@ static void r8153_set_rx_early_size(struct r8152 *tp)
ocp_data / 8);
break;
case RTL_VER_16:
- case RTL_VER_17:
+ case RTL_VER_17_QFN68:
+ case RTL_VER_17_QFN100:
ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_SIZE,
ocp_data / 16);
break;
@@ -3812,6 +3820,8 @@ static void rtl_rx_vlan_en(struct r8152 *tp, bool enable)
case RTL_VER_13:
case RTL_VER_15:
case RTL_VER_16:
+ case RTL_VER_17_QFN68:
+ case RTL_VER_17_QFN100:
default:
if (enable)
ocp_word_set_bits(tp, MCU_TYPE_PLA, PLA_RCR1,
@@ -4492,6 +4502,8 @@ static void r8153_teredo_off(struct r8152 *tp)
case RTL_VER_14:
case RTL_VER_15:
case RTL_VER_16:
+ case RTL_VER_17_QFN68:
+ case RTL_VER_17_QFN100:
default:
/* The bit 0 ~ 7 are relative with teredo settings. They are
* W1C (write 1 to clear), so set all 1 to disable it.
@@ -4546,7 +4558,8 @@ static void rtl_clear_bp(struct r8152 *tp, u16 type)
break;
case RTL_VER_14:
case RTL_VER_16:
- case RTL_VER_17:
+ case RTL_VER_17_QFN68:
+ case RTL_VER_17_QFN100:
default:
ocp_write_word(tp, type, USB_BP2_EN, 0);
bp_num = 16;
@@ -4658,7 +4671,8 @@ static bool rtl8152_is_fw_phy_speed_up_ok(struct r8152 *tp, struct fw_phy_speed_
case RTL_VER_13:
case RTL_VER_15:
case RTL_VER_16:
- case RTL_VER_17:
+ case RTL_VER_17_QFN68:
+ case RTL_VER_17_QFN100:
default:
break;
}
@@ -5818,7 +5832,8 @@ static void rtl_eee_enable(struct r8152 *tp, bool enable)
case RTL_VER_13:
case RTL_VER_15:
case RTL_VER_16:
- case RTL_VER_17:
+ case RTL_VER_17_QFN68:
+ case RTL_VER_17_QFN100:
if (enable) {
r8156_eee_en(tp, true);
ocp_reg_write(tp, OCP_EEE_ADV, tp->eee_adv);
@@ -6009,7 +6024,8 @@ static void rtl_fc_pause_pkt_en(struct r8152 *tp, u16 speed)
ocp_word_set_bits(tp, MCU_TYPE_USB, USB_FW_TASK, FC_PATCH_TASK);
break;
case RTL_VER_16:
- case RTL_VER_17:
+ 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;
@@ -6506,7 +6522,7 @@ static int rtl8156_enable(struct r8152 *tp)
set_tx_qlen(tp);
rtl_set_eee_plus(tp);
- if (tp->version >= RTL_VER_12 && tp->version <= RTL_VER_17)
+ if (tp->version >= RTL_VER_12 && tp->version <= RTL_VER_17_QFN100)
ocp_word_clr_bits(tp, MCU_TYPE_USB, USB_RX_AGGR_NUM, RX_AGGR_NUM_MASK);
r8153_set_rx_early_timeout(tp);
@@ -7002,7 +7018,8 @@ static void rtl8156_up(struct r8152 *tp)
ocp_word_set_bits(tp, MCU_TYPE_USB, 0xd3ca, BIT(15));
break;
case RTL_VER_16:
- case RTL_VER_17:
+ case RTL_VER_17_QFN68:
+ case RTL_VER_17_QFN100:
/* Enable Clear_SDR */
ocp_byte_set_bits(tp, MCU_TYPE_USB, 0xd378, BIT(7));
/* Clear SDR bit */
@@ -7046,7 +7063,8 @@ static void rtl8156_down(struct r8152 *tp)
switch (tp->version) {
case RTL_VER_16:
- case RTL_VER_17:
+ case RTL_VER_17_QFN68:
+ case RTL_VER_17_QFN100:
ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, 1526);
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, 10 * 1024 / 64);
break;
@@ -8252,7 +8270,8 @@ static void r8157_hw_phy_cfg(struct r8152 *tp)
sram2_write_w0w1(tp, 0x809d, 0xff00, 0x5000);
break;
- case RTL_VER_17:
+ case RTL_VER_17_QFN68:
+ case RTL_VER_17_QFN100:
/* Disable bypass turn off clk in ALDPS */
ocp_byte_clr_bits(tp, MCU_TYPE_PLA, 0xd3c8, BIT(0));
@@ -8646,7 +8665,8 @@ static void r8157_init(struct r8152 *tp)
return;
switch (tp->version) {
- case RTL_VER_17:
+ case RTL_VER_17_QFN68:
+ case RTL_VER_17_QFN100:
if (r8159_wait_backup_restore(tp)) {
rtl_set_inaccessible(tp);
dev_err(&tp->intf->dev,
@@ -8693,7 +8713,8 @@ static void r8157_init(struct r8152 *tp)
ocp_word_clr_bits(tp, MCU_TYPE_USB, 0xcd06, BIT(11));
switch (tp->version) {
- case RTL_VER_17:
+ case RTL_VER_17_QFN68:
+ case RTL_VER_17_QFN100:
/* Disable FW u1u2 patch option */
ocp_byte_clr_bits(tp, MCU_TYPE_USB, 0xb9a6, BIT(0));
break;
@@ -8731,7 +8752,11 @@ static void r8157_init(struct r8152 *tp)
ocp_byte_clr_bits(tp, MCU_TYPE_USB, 0xd4ae, BIT(1));
switch (tp->version) {
- case RTL_VER_17:
+ case RTL_VER_17_QFN68:
+ /* Enable u2phy backup restore patch */
+ ocp_byte_set_bits(tp, MCU_TYPE_USB, 0xb99c, BIT(0));
+ fallthrough;
+ case RTL_VER_17_QFN100:
/* Enable u3phy patch backup */
ocp_write_word(tp, MCU_TYPE_USB, 0xb9a2, 0x0448);
break;
@@ -10125,7 +10150,8 @@ static int rtl_ops_init(struct r8152 *tp)
r8157_desc_init(tp);
break;
- case RTL_VER_17:
+ case RTL_VER_17_QFN68:
+ case RTL_VER_17_QFN100:
tp->eee_en = true;
tp->eee_adv = MDIO_EEE_100TX | MDIO_EEE_1000T | MDIO_EEE_10GT;
tp->eee_adv2 = MDIO_EEE_2_5GT | MDIO_EEE_5GT;
@@ -10217,7 +10243,8 @@ static int rtl_fw_init(struct r8152 *tp)
case RTL_VER_16:
rtl_fw->fw_name = FIRMWARE_8157_1;
break;
- case RTL_VER_17:
+ case RTL_VER_17_QFN68:
+ case RTL_VER_17_QFN100:
rtl_fw->fw_name = FIRMWARE_8159_1;
break;
default:
@@ -10227,9 +10254,38 @@ static int rtl_fw_init(struct r8152 *tp)
return 0;
}
+static u32 __rtl_get_pkg_det(struct usb_device *udev)
+{
+ u32 pkg_det = 0;
+ __le32 *tmp;
+ int ret, i;
+
+ tmp = kmalloc_obj(*tmp);
+ if (!tmp)
+ return 0;
+
+ for (i = 0, ret = 0; i < 3 && ret != 4; i++)
+ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ RTL8152_REQ_GET_REGS, RTL8152_REQT_READ,
+ PLA_PKG_DET, MCU_TYPE_PLA, tmp,
+ sizeof(*tmp), USB_CTRL_GET_TIMEOUT);
+
+ if (ret == sizeof(*tmp)) {
+ if (i != 1)
+ dev_warn(&udev->dev,
+ "Needed %d retries to read package\n", i - 1);
+
+ pkg_det = __le32_to_cpu(*tmp) & PKG_MASK;
+ }
+
+ kfree(tmp);
+ return pkg_det;
+}
+
static u8 __rtl_get_hw_ver(struct usb_device *udev)
{
u32 ocp_data = 0;
+ u32 pkg_det = 0;
__le32 *tmp;
u8 version;
int ret;
@@ -10312,7 +10368,16 @@ static u8 __rtl_get_hw_ver(struct usb_device *udev)
version = RTL_VER_16;
break;
case 0x2020:
- version = RTL_VER_17;
+ pkg_det = __rtl_get_pkg_det(udev);
+ if (pkg_det == 0x1e || pkg_det == 0x1c) {
+ version = RTL_VER_17_QFN68;
+ } else if (pkg_det == 0x18 || pkg_det == 0x1a) {
+ version = RTL_VER_17_QFN100;
+ } else {
+ version = RTL_VER_UNKNOWN;
+ dev_info(&udev->dev, "Unknown package 0x%04x\n",
+ pkg_det);
+ }
break;
default:
version = RTL_VER_UNKNOWN;
@@ -10471,7 +10536,8 @@ static int rtl8152_probe_once(struct usb_interface *intf,
case RTL_VER_13:
case RTL_VER_15:
case RTL_VER_16:
- case RTL_VER_17:
+ case RTL_VER_17_QFN68:
+ case RTL_VER_17_QFN100:
netdev->max_mtu = size_to_mtu(16 * 1024);
break;
case RTL_VER_01:
--
2.34.1
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH net-next v8 08/11] r8152: split rtl8156_enable/up/down into per-generation functions
2026-11-10 3:24 [PATCH net-next v8 00/11] r8152: refactor and extend RTL8157/8159 support Chih Kai Hsu
` (6 preceding siblings ...)
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 ` 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
` (3 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Chih Kai Hsu @ 2026-11-10 3:24 UTC (permalink / raw)
To: davem, kuba
Cc: netdev, nic_swsd, linux-kernel, linux-usb, edumazet, bjorn,
pabeni, hsu.chih.kai, andrew+netdev, mail
rtl8156_enable(), rtl8156_up() and rtl8156_down() had accumulated
tp->version range checks to cover RTL8156, RTL8156B, and
RTL8157/RTL8159, including an early bail-out in rtl8156_enable()
that skipped most of the function body for RTL8157/RTL8159. The
result hides which settings belong to which chip, so chip-specific
register differences cannot be reviewed, and cannot be added without
touching the other families.
Give each generation its own enable callback: rtl8156_enable() for
RTL8156 (VER_10/11), rtl8156b_enable() for RTL8156B (VER_12/13/15),
and rtl8157_enable() for RTL8157/RTL8159 (VER_16/17). RTL8157/RTL8159
also get their own rtl8157_up()/rtl8157_down(); RTL8156 and RTL8156B
still share rtl8156_up()/rtl8156_down().
The four chips share most of the up/down sequence, so move it into
r8156_exit_oob() and r8156_enter_oob(), as RTL8152B/8153 do.
Likewise, rtl8156_enable() and rtl8156b_enable() share the idle
spin-down and L1 NYET steps, so move those into small helpers. The
FC patch restart is also done by rtl8153_enable(), so its helper,
rtl_fc_patch_restart(), is shared with it.
Each extracted function reproduces what its chips already did, with
the guards that were true for them inlined and the ones that were
false dropped as unreachable.
No functional change intended.
Signed-off-by: Chih Kai Hsu <hsu.chih.kai@realtek.com>
---
drivers/net/usb/r8152.c | 290 +++++++++++++++++++++++++---------------
1 file changed, 185 insertions(+), 105 deletions(-)
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index b6f252722a5eb..6adc198bc92ab 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -3714,6 +3714,13 @@ static void r8153_set_rx_early_size(struct r8152 *tp)
}
}
+static void rtl_fc_patch_restart(struct r8152 *tp)
+{
+ ocp_word_clr_bits(tp, MCU_TYPE_USB, USB_FW_TASK, FC_PATCH_TASK);
+ usleep_range(1000, 2000);
+ ocp_word_set_bits(tp, MCU_TYPE_USB, USB_FW_TASK, FC_PATCH_TASK);
+}
+
static int rtl8153_enable(struct r8152 *tp)
{
if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
@@ -3729,9 +3736,7 @@ static int rtl8153_enable(struct r8152 *tp)
switch (tp->version) {
case RTL_VER_09:
case RTL_VER_14:
- ocp_word_clr_bits(tp, MCU_TYPE_USB, USB_FW_TASK, FC_PATCH_TASK);
- usleep_range(1000, 2000);
- ocp_word_set_bits(tp, MCU_TYPE_USB, USB_FW_TASK, FC_PATCH_TASK);
+ rtl_fc_patch_restart(tp);
break;
default:
break;
@@ -6509,6 +6514,28 @@ static void r8156_fc_parameter(struct r8152 *tp)
ocp_write_word(tp, MCU_TYPE_PLA, PLA_RX_FIFO_EMPTY, pause_off / 16);
}
+static void r8156_idle_spdwn_en(struct r8152 *tp, u16 speed)
+{
+ if (speed & _2500bps)
+ ocp_word_clr_bits(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4,
+ IDLE_SPDWN_EN);
+ else
+ ocp_word_set_bits(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4,
+ IDLE_SPDWN_EN);
+}
+
+static void r8156_l1_nyet_hird(struct r8152 *tp, u16 speed)
+{
+ if (tp->udev->speed != USB_SPEED_HIGH)
+ return;
+
+ /* USB 0xb45e[3:0] l1_nyet_hird */
+ if (is_flow_control(speed))
+ ocp_word_w0w1(tp, MCU_TYPE_USB, USB_L1_CTRL, 0xf, 0xf);
+ else
+ ocp_word_w0w1(tp, MCU_TYPE_USB, USB_L1_CTRL, 0xf, 0x1);
+}
+
static int rtl8156_enable(struct r8152 *tp)
{
u16 speed;
@@ -6516,53 +6543,50 @@ static int rtl8156_enable(struct r8152 *tp)
if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
return -ENODEV;
- if (tp->version < RTL_VER_12)
- r8156_fc_parameter(tp);
+ r8156_fc_parameter(tp);
set_tx_qlen(tp);
rtl_set_eee_plus(tp);
-
- if (tp->version >= RTL_VER_12 && tp->version <= RTL_VER_17_QFN100)
- ocp_word_clr_bits(tp, MCU_TYPE_USB, USB_RX_AGGR_NUM, RX_AGGR_NUM_MASK);
-
r8153_set_rx_early_timeout(tp);
r8153_set_rx_early_size(tp);
speed = rtl8152_get_speed(tp);
+ rtl_set_ifg(tp, speed);
- if (tp->version >= RTL_VER_16)
- rtl_fc_pause_pkt_en(tp, speed);
+ r8156_idle_spdwn_en(tp, speed);
- rtl_set_ifg(tp, speed);
+ if (speed & _1000bps)
+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEE_TXTWSYS, 0x11);
+ else if (speed & _500bps)
+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEE_TXTWSYS, 0x3d);
- if (tp->version >= RTL_VER_16)
- return rtl_enable(tp);
+ r8156_l1_nyet_hird(tp, speed);
+ rtl_fc_patch_restart(tp);
- if (speed & _2500bps)
- ocp_word_clr_bits(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4,
- IDLE_SPDWN_EN);
- else
- ocp_word_set_bits(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4,
- IDLE_SPDWN_EN);
+ return rtl_enable(tp);
+}
- if (tp->version < RTL_VER_12) {
- if (speed & _1000bps)
- ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEE_TXTWSYS, 0x11);
- else if (speed & _500bps)
- ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEE_TXTWSYS, 0x3d);
- }
+static int rtl8156b_enable(struct r8152 *tp)
+{
+ u16 speed;
- if (tp->udev->speed == USB_SPEED_HIGH) {
- /* USB 0xb45e[3:0] l1_nyet_hird */
- if (is_flow_control(speed))
- ocp_word_w0w1(tp, MCU_TYPE_USB, USB_L1_CTRL, 0xf, 0xf);
- else
- ocp_word_w0w1(tp, MCU_TYPE_USB, USB_L1_CTRL, 0xf, 0x1);
- }
+ if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
+ return -ENODEV;
- ocp_word_clr_bits(tp, MCU_TYPE_USB, USB_FW_TASK, FC_PATCH_TASK);
- usleep_range(1000, 2000);
- ocp_word_set_bits(tp, MCU_TYPE_USB, USB_FW_TASK, FC_PATCH_TASK);
+ set_tx_qlen(tp);
+ rtl_set_eee_plus(tp);
+
+ ocp_word_clr_bits(tp, MCU_TYPE_USB, USB_RX_AGGR_NUM, RX_AGGR_NUM_MASK);
+
+ r8153_set_rx_early_timeout(tp);
+ r8153_set_rx_early_size(tp);
+
+ speed = rtl8152_get_speed(tp);
+ rtl_set_ifg(tp, speed);
+
+ r8156_idle_spdwn_en(tp, speed);
+ r8156_l1_nyet_hird(tp, speed);
+ rtl_fc_patch_restart(tp);
return rtl_enable(tp);
}
@@ -6575,6 +6599,29 @@ static void rtl8156_disable(struct r8152 *tp)
rtl8153_disable(tp);
}
+static int rtl8157_enable(struct r8152 *tp)
+{
+ u16 speed;
+
+ if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
+ return -ENODEV;
+
+ set_tx_qlen(tp);
+ rtl_set_eee_plus(tp);
+
+ ocp_word_clr_bits(tp, MCU_TYPE_USB, USB_RX_AGGR_NUM, RX_AGGR_NUM_MASK);
+
+ r8153_set_rx_early_timeout(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);
+}
+
static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u32 speed, u8 duplex,
u32 advertising)
{
@@ -6929,38 +6976,8 @@ static void rtl8156_change_mtu(struct r8152 *tp)
ALIGN(rx_max_size + tp->tx_desc.size, 1024) / 16);
}
-static void rtl8157_change_mtu(struct r8152 *tp)
+static void r8156_exit_oob(struct r8152 *tp)
{
- u32 max_pkt_size = mtu_to_size(tp->netdev->mtu);
- u32 ocp_data;
-
- ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, max_pkt_size);
-
- /* Use at least 10K for MTPS */
- ocp_data = max_t(u32, max_pkt_size, 10 * 1024) / 64;
-
- /* 16 * 1024 / 64 = 0x100, so the max is 0xff for 8 bits data */
- ocp_data = min_t(u32, ocp_data, 0xff);
-
- ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, ocp_data);
- r8156_fc_parameter(tp);
-
- /* TX share fifo free credit full threshold */
- ocp_write_word(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, 512 / 64);
- ocp_write_word(tp, MCU_TYPE_PLA, PLA_TXFIFO_FULL,
- ALIGN(max_pkt_size + tp->tx_desc.size, 1024) / 16);
-}
-
-static void rtl8156_up(struct r8152 *tp)
-{
- if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
- return;
-
- r8153b_u1u2en(tp, false);
- if (tp->version < RTL_VER_16)
- r8153_u2p3en(tp, false);
- r8153_aldps_en(tp, false);
-
rxdy_gated_en(tp, true);
r8153_teredo_off(tp);
@@ -6992,10 +7009,20 @@ static void rtl8156_up(struct r8152 *tp)
/* share FIFO settings */
ocp_word_w0w1(tp, MCU_TYPE_PLA, PLA_RXFIFO_FULL, RXFIFO_FULL_MASK,
0x08);
+}
- if (tp->version < RTL_VER_16)
- ocp_word_clr_bits(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3,
- PLA_MCU_SPDWN_EN);
+static void rtl8156_up(struct r8152 *tp)
+{
+ if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
+ return;
+
+ r8153b_u1u2en(tp, false);
+ r8153_u2p3en(tp, false);
+ r8153_aldps_en(tp, false);
+
+ r8156_exit_oob(tp);
+
+ ocp_word_clr_bits(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, PLA_MCU_SPDWN_EN);
ocp_word_clr_bits(tp, MCU_TYPE_USB, USB_SPEED_OPTION,
RG_PWRDN_EN | ALL_SPEED_OFF);
@@ -7008,8 +7035,7 @@ static void rtl8156_up(struct r8152 *tp)
}
r8153_aldps_en(tp, true);
- if (tp->version < RTL_VER_16)
- r8153_u2p3en(tp, true);
+ r8153_u2p3en(tp, true);
switch (tp->version) {
case RTL_VER_13:
@@ -7017,40 +7043,16 @@ static void rtl8156_up(struct r8152 *tp)
/* Enable Clear_SDR */
ocp_word_set_bits(tp, MCU_TYPE_USB, 0xd3ca, BIT(15));
break;
- case RTL_VER_16:
- case RTL_VER_17_QFN68:
- case RTL_VER_17_QFN100:
- /* Enable Clear_SDR */
- ocp_byte_set_bits(tp, MCU_TYPE_USB, 0xd378, BIT(7));
- /* Clear SDR bit */
- ocp_word_clr_bits(tp, MCU_TYPE_USB, 0xcd06, BIT(15));
- break;
default:
break;
}
- if (tp->version < RTL_VER_16 && tp->udev->speed >= USB_SPEED_SUPER)
+ if (tp->udev->speed >= USB_SPEED_SUPER)
r8153b_u1u2en(tp, true);
}
-static void rtl8156_down(struct r8152 *tp)
+static void r8156_enter_oob(struct r8152 *tp)
{
- if (test_bit(RTL8152_INACCESSIBLE, &tp->flags)) {
- rtl_drop_queued_tx(tp);
- return;
- }
-
- if (tp->version < RTL_VER_16)
- ocp_word_set_bits(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3,
- PLA_MCU_SPDWN_EN);
-
- r8153b_u1u2en(tp, false);
- if (tp->version < RTL_VER_16) {
- r8153_u2p3en(tp, false);
- r8153b_power_cut_en(tp, false);
- }
- r8153_aldps_en(tp, false);
-
ocp_byte_clr_bits(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, NOW_IS_OOB);
/* RX FIFO settings for OOB */
@@ -7092,7 +7094,85 @@ static void rtl8156_down(struct r8152 *tp)
ocp_dword_set_bits(tp, MCU_TYPE_PLA, PLA_RCR,
RCR_APM | RCR_AM | RCR_AB);
+}
+
+static void rtl8156_down(struct r8152 *tp)
+{
+ if (test_bit(RTL8152_INACCESSIBLE, &tp->flags)) {
+ rtl_drop_queued_tx(tp);
+ return;
+ }
+ ocp_word_set_bits(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3,
+ PLA_MCU_SPDWN_EN);
+
+ r8153b_u1u2en(tp, false);
+ r8153_u2p3en(tp, false);
+ r8153b_power_cut_en(tp, false);
+ r8153_aldps_en(tp, false);
+ r8156_enter_oob(tp);
+ r8153_aldps_en(tp, true);
+}
+
+static void rtl8157_change_mtu(struct r8152 *tp)
+{
+ u32 max_pkt_size = mtu_to_size(tp->netdev->mtu);
+ u32 ocp_data;
+
+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, max_pkt_size);
+
+ /* Use at least 10K for MTPS */
+ ocp_data = max_t(u32, max_pkt_size, 10 * 1024) / 64;
+
+ /* 16 * 1024 / 64 = 0x100, so the max is 0xff for 8 bits data */
+ ocp_data = min_t(u32, ocp_data, 0xff);
+
+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, ocp_data);
+ r8156_fc_parameter(tp);
+
+ /* TX share fifo free credit full threshold */
+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, 512 / 64);
+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_TXFIFO_FULL,
+ ALIGN(max_pkt_size + tp->tx_desc.size, 1024) / 16);
+}
+
+static void rtl8157_up(struct r8152 *tp)
+{
+ if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
+ return;
+
+ r8153b_u1u2en(tp, false);
+ r8153_aldps_en(tp, false);
+ r8156_exit_oob(tp);
+
+ ocp_word_clr_bits(tp, MCU_TYPE_USB, USB_SPEED_OPTION,
+ RG_PWRDN_EN | ALL_SPEED_OFF);
+
+ ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, 0x00600400);
+
+ if (tp->saved_wolopts != __rtl_get_wol(tp)) {
+ netif_warn(tp, ifup, tp->netdev, "wol setting is changed\n");
+ __rtl_set_wol(tp, tp->saved_wolopts);
+ }
+
+ r8153_aldps_en(tp, true);
+
+ /* Enable Clear_SDR */
+ ocp_byte_set_bits(tp, MCU_TYPE_USB, 0xd378, BIT(7));
+ /* Clear SDR bit */
+ ocp_word_clr_bits(tp, MCU_TYPE_USB, 0xcd06, BIT(15));
+}
+
+static void rtl8157_down(struct r8152 *tp)
+{
+ if (test_bit(RTL8152_INACCESSIBLE, &tp->flags)) {
+ rtl_drop_queued_tx(tp);
+ return;
+ }
+
+ r8153b_u1u2en(tp, false);
+ r8153_aldps_en(tp, false);
+ r8156_enter_oob(tp);
r8153_aldps_en(tp, true);
}
@@ -10094,7 +10174,7 @@ static int rtl_ops_init(struct r8152 *tp)
tp->eee_adv = MDIO_EEE_1000T | MDIO_EEE_100TX;
tp->eee_adv2 = MDIO_EEE_2_5GT;
ops->init = r8156_init;
- ops->enable = rtl8156_enable;
+ ops->enable = rtl8156b_enable;
ops->disable = rtl8153_disable;
ops->up = rtl8156_up;
ops->down = rtl8156_down;
@@ -10133,10 +10213,10 @@ static int rtl_ops_init(struct r8152 *tp)
tp->eee_adv = MDIO_EEE_1000T | MDIO_EEE_100TX;
tp->eee_adv2 = MDIO_EEE_2_5GT | MDIO_EEE_5GT;
ops->init = r8157_init;
- ops->enable = rtl8156_enable;
+ ops->enable = rtl8157_enable;
ops->disable = rtl8153_disable;
- ops->up = rtl8156_up;
- ops->down = rtl8156_down;
+ ops->up = rtl8157_up;
+ ops->down = rtl8157_down;
ops->unload = rtl8157_unload;
ops->eee_get = r8153_get_eee;
ops->eee_set = r8152_set_eee;
@@ -10156,10 +10236,10 @@ static int rtl_ops_init(struct r8152 *tp)
tp->eee_adv = MDIO_EEE_100TX | MDIO_EEE_1000T | MDIO_EEE_10GT;
tp->eee_adv2 = MDIO_EEE_2_5GT | MDIO_EEE_5GT;
ops->init = r8157_init;
- ops->enable = rtl8156_enable;
+ ops->enable = rtl8157_enable;
ops->disable = rtl8153_disable;
- ops->up = rtl8156_up;
- ops->down = rtl8156_down;
+ ops->up = rtl8157_up;
+ ops->down = rtl8157_down;
ops->unload = rtl8157_unload;
ops->eee_get = r8153_get_eee;
ops->eee_set = r8152_set_eee;
--
2.34.1
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH net-next v8 09/11] r8152: split r8157_hw_phy_cfg into RTL8157 and RTL8159 variants
2026-11-10 3:24 [PATCH net-next v8 00/11] r8152: refactor and extend RTL8157/8159 support Chih Kai Hsu
` (7 preceding siblings ...)
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 ` 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
` (2 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Chih Kai Hsu @ 2026-11-10 3:24 UTC (permalink / raw)
To: davem, kuba
Cc: netdev, nic_swsd, linux-kernel, linux-usb, edumazet, bjorn,
pabeni, hsu.chih.kai, andrew+netdev, mail
r8157_hw_phy_cfg() served both RTL8157 (VER_16) and RTL8159
(VER_17_QFN68/QFN100) via a tp->version switch inside a single
function, but per the datasheet RTL8159's PHY tuning differs from
RTL8157's in more than the per-version blocks already captured.
Split it into r8157_hw_phy_cfg() (VER_16 only) and a new
r8159_hw_phy_cfg() (VER_17_QFN68/QFN100), each with its own copy of
the shared prologue/epilogue. rtl_ops_init() assigns each one to its
own chips only. Per the datasheet, RTL8159 diverges from RTL8157 in
this split in several ways:
- RTL8159 doesn't need EEE disabled before reprogramming PHY
parameters, so r8159_hw_phy_cfg() drops the rtl_eee_enable(tp,
false) call that r8157_hw_phy_cfg() keeps.
- Since EEE isn't forced off up front, r8159_hw_phy_cfg() ends with
rtl_eee_enable(tp, tp->eee_en) instead of only enabling EEE when
eee_en is set, so the configured state is applied in both
directions.
- RTL8159's EEE clock-divider and 0xa5ea encoding differ from
RTL8157's: r8159_hw_phy_cfg() clears EN_10M_CLKDIV (ups_info.
_10m_ckdiv = false) instead of setting it, and clears an extra bit
(BIT(2)) of 0xa5ea.
- "Disable bypass_turn_off_clk_in_aldps" (0xd3c8 BIT(0)) is needed by
both chips, so it moves from the VER_17-only switch case into the
shared prologue and now also runs for RTL8157.
Newly added PHY tuning parameters for RTL8159:
- shorten CLKS latency
- CMP_Timer on MP_Timer=333
- spdchg_pga1_lpf_cap
- ENET PLL jitter improvement
Moreover, change sram2 0x8ffe[15:0] = 0xf450 to 0xf4ff.
Along the way, add sram2_set_bits()/sram2_clr_bits() helpers
mirroring the existing sram_set_bits()/sram_clr_bits(), and use the
named OCP_POWER_CFG/EN_10M_PLLOFF/EN_ALDPS_PLLOFF macros in place of
the raw "ocp_reg_set_bits(tp, 0xa430, BIT(0) | BIT(1))".
Signed-off-by: Chih Kai Hsu <hsu.chih.kai@realtek.com>
---
drivers/net/usb/r8152.c | 168 ++++++++++++++++++++++++++++++++--------
1 file changed, 137 insertions(+), 31 deletions(-)
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 6adc198bc92ab..fad4473caf2a4 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -660,6 +660,7 @@ enum spd_duplex {
/* OCP_POWER_CFG */
#define EEE_CLKDIV_EN 0x8000
#define EN_ALDPS 0x0004
+#define EN_ALDPS_PLLOFF 0x0002
#define EN_10M_PLLOFF 0x0001
/* OCP_EEE_CONFIG1 */
@@ -1969,6 +1970,16 @@ static void sram2_write_w0w1(struct r8152 *tp, u16 addr, u16 clear, u16 set)
ocp_reg_write(tp, OCP_SRAM2_DATA, data);
}
+static void sram2_set_bits(struct r8152 *tp, u16 addr, u16 set)
+{
+ sram2_write_w0w1(tp, addr, 0, set);
+}
+
+static void sram2_clr_bits(struct r8152 *tp, u16 addr, u16 clear)
+{
+ sram2_write_w0w1(tp, addr, clear, 0);
+}
+
static void r8152_mdio_clr_bit(struct r8152 *tp, u16 addr, u16 clear)
{
int data;
@@ -8223,11 +8234,14 @@ static void r8157_hw_phy_cfg(struct r8152 *tp)
ocp_word_clr_bits(tp, MCU_TYPE_PLA, PLA_PHY_PWR, PFM_PWM_SWITCH);
/* Advanced Power Saving parameter */
- ocp_reg_set_bits(tp, 0xa430, BIT(0) | BIT(1));
+ ocp_reg_set_bits(tp, OCP_POWER_CFG, EN_10M_PLLOFF | EN_ALDPS_PLLOFF);
/* Disable ALDPS force mode */
ocp_reg_clr_bits(tp, 0xa44a, BIT(2));
+ /* Disable bypass_turn_off_clk_in_aldps */
+ ocp_byte_clr_bits(tp, MCU_TYPE_PLA, 0xd3c8, BIT(0));
+
switch (tp->version) {
case RTL_VER_16:
/* XG_INRX parameter */
@@ -8243,7 +8257,7 @@ static void r8157_hw_phy_cfg(struct r8152 *tp)
sram2_write_w0w1(tp, 0x8078, 0xff00, 0x3000);
/* green mode */
- sram2_write_w0w1(tp, 0x89e9, 0xff00, 0);
+ sram2_clr_bits(tp, 0x89e9, 0xff00);
sram2_write_w0w1(tp, 0x8ffd, 0xff00, 0x0100);
sram2_write_w0w1(tp, 0x8ffe, 0xff00, 0x0200);
sram2_write_w0w1(tp, 0x8fff, 0xff00, 0x0400);
@@ -8349,12 +8363,85 @@ static void r8157_hw_phy_cfg(struct r8152 *tp)
sram2_write_w0w1(tp, 0x807c, 0xff00, 0x5000);
sram2_write_w0w1(tp, 0x809d, 0xff00, 0x5000);
break;
+ default:
+ break;
+ }
+
+ if (rtl_phy_patch_request(tp, true, true))
+ return;
+
+ ocp_word_set_bits(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4, EEE_SPDWN_EN);
+
+ ocp_reg_w0w1(tp, OCP_DOWN_SPEED, EN_EEE_100 | EN_EEE_1000, EN_10M_CLKDIV);
+
+ tp->ups_info._10m_ckdiv = true;
+ tp->ups_info.eee_plloff_100 = false;
+ tp->ups_info.eee_plloff_giga = false;
+
+ ocp_reg_set_bits(tp, OCP_POWER_CFG, EEE_CLKDIV_EN);
+ tp->ups_info.eee_ckdiv = true;
+
+ rtl_phy_patch_request(tp, false, true);
+
+ rtl_green_en(tp, test_bit(GREEN_ETHERNET, &tp->flags));
+
+ ocp_reg_clr_bits(tp, 0xa428, BIT(9));
+ ocp_reg_clr_bits(tp, 0xa5ea, BIT(0) | BIT(1));
+ tp->ups_info.lite_mode = 0;
+
+ if (tp->eee_en)
+ rtl_eee_enable(tp, true);
+
+ r8153_aldps_en(tp, true);
+ r8152b_enable_fc(tp);
+
+ set_bit(PHY_RESET, &tp->flags);
+}
+
+static void r8159_hw_phy_cfg(struct r8152 *tp)
+{
+ u16 data;
+
+ r8156b_wait_loading_flash(tp);
+
+ ocp_word_test_and_clr_bits(tp, MCU_TYPE_USB, USB_MISC_0, PCUT_STATUS);
+
+ data = r8153_phy_status(tp, 0);
+ switch (data) {
+ case PHY_STAT_EXT_INIT:
+ rtl8152_apply_firmware(tp, true);
+ ocp_reg_clr_bits(tp, 0xa466, BIT(0));
+ ocp_reg_clr_bits(tp, 0xa468, BIT(3) | BIT(1));
+ break;
+ case PHY_STAT_LAN_ON:
+ case PHY_STAT_PWRDN:
+ default:
+ rtl8152_apply_firmware(tp, false);
+ break;
+ }
+
+ r8152_mdio_test_and_clr_bit(tp, MII_BMCR, BMCR_PDOWN);
+
+ r8153_aldps_en(tp, false);
+
+ data = r8153_phy_status(tp, PHY_STAT_LAN_ON);
+ WARN_ON_ONCE(data != PHY_STAT_LAN_ON);
+ /* PFM mode */
+ ocp_word_clr_bits(tp, MCU_TYPE_PLA, PLA_PHY_PWR, PFM_PWM_SWITCH);
+
+ /* Advanced Power Saving parameter */
+ ocp_reg_set_bits(tp, OCP_POWER_CFG, EN_10M_PLLOFF | EN_ALDPS_PLLOFF);
+
+ /* Disable ALDPS force mode */
+ ocp_reg_clr_bits(tp, 0xa44a, BIT(2));
+
+ /* Disable bypass_turn_off_clk_in_aldps */
+ ocp_byte_clr_bits(tp, MCU_TYPE_PLA, 0xd3c8, BIT(0));
+
+ switch (tp->version) {
case RTL_VER_17_QFN68:
case RTL_VER_17_QFN100:
- /* Disable bypass turn off clk in ALDPS */
- ocp_byte_clr_bits(tp, MCU_TYPE_PLA, 0xd3c8, BIT(0));
-
/* Power level tuning
* test mode power level
*/
@@ -8364,22 +8451,35 @@ static void r8157_hw_phy_cfg(struct r8152 *tp)
sram_write_w0w1(tp, 0x81ae, 0xff00, 0x0f00);
sram_write_w0w1(tp, 0x81b9, 0xff00, 0xb900);
/* normal link TX filter */
- sram2_write_w0w1(tp, 0x83b0, 0x0e00, 0);
- sram2_write_w0w1(tp, 0x83c5, 0x0e00, 0);
- sram2_write_w0w1(tp, 0x83da, 0x0e00, 0);
- sram2_write_w0w1(tp, 0x83ef, 0x0e00, 0);
+ sram2_clr_bits(tp, 0x83b0, 0x0e00);
+ sram2_clr_bits(tp, 0x83c5, 0x0e00);
+ sram2_clr_bits(tp, 0x83da, 0x0e00);
+ sram2_clr_bits(tp, 0x83ef, 0x0e00);
+
+ ocp_reg_w0w1(tp, 0xbf38, 0x01f0, 0x0160);
+ ocp_reg_w0w1(tp, 0xbf3a, 0x001f, 0x0014);
+ /* shorten CLKS latency */
+ ocp_reg_clr_bits(tp, 0xbf28, BIT(14) | BIT(13));
+ ocp_reg_clr_bits(tp, 0xbf2c, BIT(15) | BIT(14));
+ /* CMP_Timer on MP_Timer=333
+ * GPHY OCP 0xbf28 bit[0] = 0x1
+ * GPHY OCP 0xbf28 bit[6:1] = 0x3
+ * GPHY OCP 0xbf28 bit[12:7] = 0x3
+ */
+ ocp_reg_w0w1(tp, 0xbf28, 0x1fff, 0x0187);
+ ocp_reg_w0w1(tp, 0xbf2a, 0x3f, 0x03);
/* AFE power saving for 2.5G & 5G */
sram_write(tp, 0x8173, 0x8620);
sram_write(tp, 0x8175, 0x8671);
- sram_write_w0w1(tp, 0x817c, 0, BIT(13));
- sram_write_w0w1(tp, 0x8187, 0, BIT(13));
- sram_write_w0w1(tp, 0x8192, 0, BIT(13));
- sram_write_w0w1(tp, 0x819d, 0, BIT(13));
- sram_write_w0w1(tp, 0x81a8, BIT(13), 0);
- sram_write_w0w1(tp, 0x81b3, BIT(13), 0);
- sram_write_w0w1(tp, 0x81be, 0, BIT(13));
+ sram_set_bits(tp, 0x817c, BIT(13));
+ sram_set_bits(tp, 0x8187, BIT(13));
+ sram_set_bits(tp, 0x8192, BIT(13));
+ sram_set_bits(tp, 0x819d, BIT(13));
+ sram_clr_bits(tp, 0x81a8, BIT(13));
+ sram_clr_bits(tp, 0x81b3, BIT(13));
+ sram_set_bits(tp, 0x81be, BIT(13));
sram_write_w0w1(tp, 0x817d, 0xff00, 0xa600);
sram_write_w0w1(tp, 0x8188, 0xff00, 0xa600);
@@ -8443,10 +8543,10 @@ static void r8157_hw_phy_cfg(struct r8152 *tp)
sram2_write_w0w1(tp, 0x84b2, 0xff00, 0x6000);
/* Training AAGC PAR (with uc2 patch) */
sram2_write(tp, 0x8ffc, 0x6008);
- sram2_write(tp, 0x8ffe, 0xf450);
+ sram2_write(tp, 0x8ffe, 0xf4ff);
/* DAC BGK */
- sram2_write_w0w1(tp, 0x8015, 0, BIT(9));
- sram2_write_w0w1(tp, 0x8016, 0, BIT(11));
+ sram2_set_bits(tp, 0x8015, BIT(9));
+ sram2_set_bits(tp, 0x8016, BIT(11));
sram2_write_w0w1(tp, 0x8fe6, 0xff00, 0x0800);
sram2_write(tp, 0x8fe4, 0x2114);
/* 10G PBO table */
@@ -8455,14 +8555,14 @@ static void r8157_hw_phy_cfg(struct r8152 *tp)
sram2_write_w0w1(tp, 0x864b, 0xff00, 0xdc00);
/* 2.5G ado power window size */
sram2_write_w0w1(tp, 0x8154, 0xc000, 0x4000);
- sram2_write_w0w1(tp, 0x8158, 0xc000, 0);
+ sram2_clr_bits(tp, 0x8158, 0xc000);
/* 10G lock far */
sram2_write(tp, 0x826c, 0xffff);
sram2_write(tp, 0x826e, 0xffff);
/* XG INRX parameter */
sram2_write_w0w1(tp, 0x8872, 0xff00, 0x0e00);
- sram_write_w0w1(tp, 0x8012, 0, BIT(11));
- sram_write_w0w1(tp, 0x8012, 0, BIT(14));
+ sram_set_bits(tp, 0x8012, BIT(11));
+ sram_set_bits(tp, 0x8012, BIT(14));
ocp_reg_set_bits(tp, 0xb576, BIT(0));
sram_write_w0w1(tp, 0x834a, 0xff00, 0x0700);
sram2_write_w0w1(tp, 0x8217, 0x3f00, 0x2a00);
@@ -8473,7 +8573,7 @@ static void r8157_hw_phy_cfg(struct r8152 *tp)
/* improve UBE */
ocp_reg_set_bits(tp, 0xbf0c, 0x7 << 11);
/* close Sparse NEC, improve connect 5EUU cable performance */
- sram2_write_w0w1(tp, 0x88de, 0xff00, 0);
+ sram2_clr_bits(tp, 0x88de, 0xff00);
/* 5G slave compatibility issue */
sram2_write(tp, 0x80b4, 0x5195);
@@ -8532,8 +8632,15 @@ static void r8157_hw_phy_cfg(struct r8152 *tp)
sram2_write(tp, 0x8ff8, 0xaa5a);
sram2_write_w0w1(tp, 0x88d5, 0xff00, 0x0200);
- break;
+ /* spdchg_pga1_lpf_cap */
+ sram_write_w0w1(tp, 0x84bb, 0xff00, 0x0a00);
+ sram_write_w0w1(tp, 0x84c0, 0xff00, 0x1600);
+
+ /* ENET PLL jitter improvement */
+ ocp_reg_w0w1(tp, 0xbf8a, 0xfc00, 0x2000);
+ ocp_reg_set_bits(tp, 0xbf88, BIT(2));
+ break;
default:
break;
}
@@ -8543,9 +8650,9 @@ static void r8157_hw_phy_cfg(struct r8152 *tp)
ocp_word_set_bits(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4, EEE_SPDWN_EN);
- ocp_reg_w0w1(tp, OCP_DOWN_SPEED, EN_EEE_100 | EN_EEE_1000, EN_10M_CLKDIV);
-
- tp->ups_info._10m_ckdiv = true;
+ ocp_reg_clr_bits(tp, OCP_DOWN_SPEED,
+ EN_EEE_100 | EN_EEE_1000 | EN_10M_CLKDIV);
+ tp->ups_info._10m_ckdiv = false;
tp->ups_info.eee_plloff_100 = false;
tp->ups_info.eee_plloff_giga = false;
@@ -8557,11 +8664,10 @@ static void r8157_hw_phy_cfg(struct r8152 *tp)
rtl_green_en(tp, test_bit(GREEN_ETHERNET, &tp->flags));
ocp_reg_clr_bits(tp, 0xa428, BIT(9));
- ocp_reg_clr_bits(tp, 0xa5ea, BIT(0) | BIT(1));
+ ocp_reg_clr_bits(tp, 0xa5ea, BIT(0) | BIT(1) | BIT(2));
tp->ups_info.lite_mode = 0;
- if (tp->eee_en)
- rtl_eee_enable(tp, true);
+ rtl_eee_enable(tp, tp->eee_en);
r8153_aldps_en(tp, true);
r8152b_enable_fc(tp);
@@ -10244,7 +10350,7 @@ static int rtl_ops_init(struct r8152 *tp)
ops->eee_get = r8153_get_eee;
ops->eee_set = r8152_set_eee;
ops->in_nway = rtl8153_in_nway;
- ops->hw_phy_cfg = r8157_hw_phy_cfg;
+ ops->hw_phy_cfg = r8159_hw_phy_cfg;
ops->autosuspend_en = rtl8157_runtime_enable;
ops->change_mtu = rtl8157_change_mtu;
tp->rx_buf_sz = 48 * 1024;
--
2.34.1
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH net-next v8 10/11] r8152: add TGPHY register access for RTL8157 and RTL8159
2026-11-10 3:24 [PATCH net-next v8 00/11] r8152: refactor and extend RTL8157/8159 support Chih Kai Hsu
` (8 preceding siblings ...)
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 ` 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
2026-11-10 5:04 ` [PATCH net-next v8 00/11] r8152: refactor and extend RTL8157/8159 support netdev-bot+sinfo
11 siblings, 0 replies; 13+ messages in thread
From: Chih Kai Hsu @ 2026-11-10 3:24 UTC (permalink / raw)
To: davem, kuba
Cc: netdev, nic_swsd, linux-kernel, linux-usb, edumazet, bjorn,
pabeni, hsu.chih.kai, andrew+netdev, mail
RTL8157 and RTL8159 have a TGPHY command channel
(USB_TGPHY_ADDR/DATA/CMD) for PHY registers that needs no OCP base
switching. Use it for these chips; older chips keep the OCP path.
Route ocp_reg_read()/ocp_reg_write() through new rtl_ops.phy_read and
phy_write hooks, set per chip.
Unlike the OCP path, a TGPHY access can fail: the busy bit can time
out, or the device can be gone. The access is then abandoned and
returns an errno (-ENODEV if the device is inaccessible). A timeout is
logged ratelimited, so a stuck busy bit does not flood the log, and
does not mark the device inaccessible, as for the ADV command channel.
The PHY accessors and the helpers built on them therefore return int,
and the callers where a failure would be taken for register content or
for success now act on it:
- rtl8152_set_pauseparam(), rtl8152_set_speed(), SIOCGMIIREG/
SIOCSMIIREG, rtl8152_get_link_ksettings(), r8153_get_eee() and
r8152_mdio_read() propagate the error. A failed write in
rtl8152_set_speed() leaves the cached advertising and a pending PHY
reset untouched. rtl8152_get_pauseparam() reports no flow control
when a read fails.
- The PHY firmware version checks skip the patch when the version
cannot be read.
- rtl_phy_patch_request() returns the errno of a failed write, and
releases PATCH_REQUEST when a later step fails, so a failed access
does not leave it asserted.
- r8153_phy_status() treats a failed read as "not ready" and keeps
polling, so one failure does not end the wait early.
- rtl8153_in_nway(), r8156_mdio_force_mode(), r8156_eee_en() and
rtl8152_fw_phy_fixup() stop on a failed read instead of using stale
data.
- read_mii_word() reports a failed read as 0. The MII library takes
the return value for register content, and an errno would look like
a BMCR with autonegotiation enabled.
The hw_phy_cfg and init sequences, the ocp_reg_*_bits() and sram_*()
callers that write PHY configuration, r8152_mmd_read() and the MII
write callback still ignore the status, as does recovery from a TGPHY
timeout. These are left to a follow-up series.
Older chips are unaffected, as r8152_phy_read() always succeeds.
Signed-off-by: Chih Kai Hsu <hsu.chih.kai@realtek.com>
---
drivers/net/usb/r8152.c | 544 ++++++++++++++++++++++++++++++----------
1 file changed, 417 insertions(+), 127 deletions(-)
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index fad4473caf2a4..703ec5483778b 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -163,6 +163,9 @@
#define USB_ADV_ADDR 0xd5d6
#define USB_ADV_DATA 0xd5d8
#define USB_ADV_CMD 0xd5dc
+#define USB_TGPHY_ADDR 0xd630
+#define USB_TGPHY_DATA 0xd632
+#define USB_TGPHY_CMD 0xd634
#define USB_UPS_CTRL 0xd800
#define USB_POWER_CUT 0xd80a
#define USB_MISC_0 0xd81a
@@ -516,6 +519,10 @@
#define ADV_CMD_WR BIT(1)
#define ADV_CMD_IP BIT(2)
+/* USB_TGPHY_CMD */
+#define TGPHY_CMD_BUSY BIT(0)
+#define TGPHY_CMD_WR BIT(1)
+
/* USB_UPS_CTRL */
#define POWER_CUT 0x0100
@@ -964,6 +971,8 @@ struct r8152 {
void (*hw_phy_cfg)(struct r8152 *tp);
void (*autosuspend_en)(struct r8152 *tp, bool enable);
void (*change_mtu)(struct r8152 *tp);
+ int (*phy_read)(struct r8152 *tp, u16 addr, u16 *data);
+ int (*phy_write)(struct r8152 *tp, u16 addr, u16 data);
} rtl_ops;
struct ups_info {
@@ -1643,7 +1652,7 @@ static void ocp_write_byte(struct r8152 *tp, u16 type, u16 index, u32 data)
generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type);
}
-static u16 ocp_reg_read(struct r8152 *tp, u16 addr)
+static int r8152_phy_read(struct r8152 *tp, u16 addr, u16 *data)
{
u16 ocp_base, ocp_index;
@@ -1654,10 +1663,12 @@ static u16 ocp_reg_read(struct r8152 *tp, u16 addr)
}
ocp_index = (addr & 0x0fff) | 0xb000;
- return ocp_read_word(tp, MCU_TYPE_PLA, ocp_index);
+ *data = ocp_read_word(tp, MCU_TYPE_PLA, ocp_index);
+
+ return 0;
}
-static void ocp_reg_write(struct r8152 *tp, u16 addr, u16 data)
+static int r8152_phy_write(struct r8152 *tp, u16 addr, u16 data)
{
u16 ocp_base, ocp_index;
@@ -1669,16 +1680,33 @@ static void ocp_reg_write(struct r8152 *tp, u16 addr, u16 data)
ocp_index = (addr & 0x0fff) | 0xb000;
ocp_write_word(tp, MCU_TYPE_PLA, ocp_index, data);
+
+ return 0;
+}
+
+static int ocp_reg_read(struct r8152 *tp, u16 addr, u16 *data)
+{
+ return tp->rtl_ops.phy_read(tp, addr, data);
+}
+
+static int ocp_reg_write(struct r8152 *tp, u16 addr, u16 data)
+{
+ return tp->rtl_ops.phy_write(tp, addr, data);
}
-static inline void r8152_mdio_write(struct r8152 *tp, u32 reg_addr, u32 value)
+static inline int r8152_mdio_write(struct r8152 *tp, u32 reg_addr, u32 value)
{
- ocp_reg_write(tp, OCP_BASE_MII + reg_addr * 2, value);
+ return ocp_reg_write(tp, OCP_BASE_MII + reg_addr * 2, value);
}
-static inline int r8152_mdio_read(struct r8152 *tp, u32 reg_addr)
+static int r8152_mdio_read(struct r8152 *tp, u32 reg_addr)
{
- return ocp_reg_read(tp, OCP_BASE_MII + reg_addr * 2);
+ u16 data;
+ int ret;
+
+ ret = ocp_reg_read(tp, OCP_BASE_MII + reg_addr * 2, &data);
+
+ return ret < 0 ? ret : data;
}
static int wait_cmd_ready(struct r8152 *tp, u16 cmd)
@@ -1797,16 +1825,32 @@ static int rtl_ip_set_bits(struct r8152 *tp, u16 addr, u32 set)
return rtl_ip_w0w1(tp, addr, 0, set);
}
-static void sram_write(struct r8152 *tp, u16 addr, u16 data)
+static int sram_write(struct r8152 *tp, u16 addr, u16 data)
{
- ocp_reg_write(tp, OCP_SRAM_ADDR, addr);
- ocp_reg_write(tp, OCP_SRAM_DATA, data);
+ int ret;
+
+ ret = ocp_reg_write(tp, OCP_SRAM_ADDR, addr);
+ if (ret < 0)
+ goto out;
+
+ ret = ocp_reg_write(tp, OCP_SRAM_DATA, data);
+
+out:
+ return ret;
}
-static u16 sram_read(struct r8152 *tp, u16 addr)
+static int sram_read(struct r8152 *tp, u16 addr, u16 *data)
{
- ocp_reg_write(tp, OCP_SRAM_ADDR, addr);
- return ocp_reg_read(tp, OCP_SRAM_DATA);
+ int ret;
+
+ ret = ocp_reg_write(tp, OCP_SRAM_ADDR, addr);
+ if (ret < 0)
+ goto out;
+
+ ret = ocp_reg_read(tp, OCP_SRAM_DATA, data);
+
+out:
+ return ret;
}
static int read_mii_word(struct net_device *netdev, int phy_id, int reg)
@@ -1822,7 +1866,10 @@ static int read_mii_word(struct net_device *netdev, int phy_id, int reg)
ret = r8152_mdio_read(tp, reg);
- return ret;
+ /* The MII library takes the return value for register content,
+ * so a failed read must not be passed on as an errno.
+ */
+ return ret < 0 ? 0 : ret;
}
static
@@ -1911,100 +1958,221 @@ static void ocp_byte_set_bits(struct r8152 *tp, u16 type, u16 index, u8 set)
ocp_byte_w0w1(tp, type, index, 0, set);
}
-static void ocp_reg_w0w1(struct r8152 *tp, u16 addr, u16 clear, u16 set)
+static int ocp_reg_w0w1(struct r8152 *tp, u16 addr, u16 clear, u16 set)
{
u16 data;
+ int ret;
+
+ ret = ocp_reg_read(tp, addr, &data);
+ if (ret < 0)
+ goto out;
- data = ocp_reg_read(tp, addr);
data = (data & ~clear) | set;
- ocp_reg_write(tp, addr, data);
+ ret = ocp_reg_write(tp, addr, data);
+
+out:
+ return ret;
}
-static void ocp_reg_clr_bits(struct r8152 *tp, u16 addr, u16 clear)
+static int ocp_reg_clr_bits(struct r8152 *tp, u16 addr, u16 clear)
{
- ocp_reg_w0w1(tp, addr, clear, 0);
+ return ocp_reg_w0w1(tp, addr, clear, 0);
}
-static void ocp_reg_set_bits(struct r8152 *tp, u16 addr, u16 set)
+static int ocp_reg_set_bits(struct r8152 *tp, u16 addr, u16 set)
{
- ocp_reg_w0w1(tp, addr, 0, set);
+ return ocp_reg_w0w1(tp, addr, 0, set);
}
-static void sram_write_w0w1(struct r8152 *tp, u16 addr, u16 clear, u16 set)
+static int sram_write_w0w1(struct r8152 *tp, u16 addr, u16 clear, u16 set)
{
u16 data;
+ int ret;
+
+ ret = sram_read(tp, addr, &data);
+ if (ret < 0)
+ goto out;
- data = sram_read(tp, addr);
data = (data & ~clear) | set;
- ocp_reg_write(tp, OCP_SRAM_DATA, data);
+ ret = ocp_reg_write(tp, OCP_SRAM_DATA, data);
+
+out:
+ return ret;
}
-static void sram_clr_bits(struct r8152 *tp, u16 addr, u16 clear)
+static int sram_clr_bits(struct r8152 *tp, u16 addr, u16 clear)
{
- sram_write_w0w1(tp, addr, clear, 0);
+ return sram_write_w0w1(tp, addr, clear, 0);
}
-static void sram_set_bits(struct r8152 *tp, u16 addr, u16 set)
+static int sram_set_bits(struct r8152 *tp, u16 addr, u16 set)
{
- sram_write_w0w1(tp, addr, 0, set);
+ return sram_write_w0w1(tp, addr, 0, set);
}
-static void sram2_write(struct r8152 *tp, u16 addr, u16 data)
+static int sram2_write(struct r8152 *tp, u16 addr, u16 data)
{
- ocp_reg_write(tp, OCP_SRAM2_ADDR, addr);
- ocp_reg_write(tp, OCP_SRAM2_DATA, data);
+ int ret;
+
+ ret = ocp_reg_write(tp, OCP_SRAM2_ADDR, addr);
+ if (ret < 0)
+ goto out;
+
+ ret = ocp_reg_write(tp, OCP_SRAM2_DATA, data);
+
+out:
+ return ret;
}
-static u16 sram2_read(struct r8152 *tp, u16 addr)
+static int sram2_read(struct r8152 *tp, u16 addr, u16 *data)
{
- ocp_reg_write(tp, OCP_SRAM2_ADDR, addr);
- return ocp_reg_read(tp, OCP_SRAM2_DATA);
+ int ret;
+
+ ret = ocp_reg_write(tp, OCP_SRAM2_ADDR, addr);
+ if (ret < 0)
+ goto out;
+
+ ret = ocp_reg_read(tp, OCP_SRAM2_DATA, data);
+
+out:
+ return ret;
}
-static void sram2_write_w0w1(struct r8152 *tp, u16 addr, u16 clear, u16 set)
+static int sram2_write_w0w1(struct r8152 *tp, u16 addr, u16 clear, u16 set)
{
u16 data;
+ int ret;
+
+ ret = sram2_read(tp, addr, &data);
+ if (ret < 0)
+ goto out;
- data = sram2_read(tp, addr);
data = (data & ~clear) | set;
- ocp_reg_write(tp, OCP_SRAM2_DATA, data);
+ ret = ocp_reg_write(tp, OCP_SRAM2_DATA, data);
+
+out:
+ return ret;
}
-static void sram2_set_bits(struct r8152 *tp, u16 addr, u16 set)
+static int sram2_set_bits(struct r8152 *tp, u16 addr, u16 set)
{
- sram2_write_w0w1(tp, addr, 0, set);
+ return sram2_write_w0w1(tp, addr, 0, set);
}
-static void sram2_clr_bits(struct r8152 *tp, u16 addr, u16 clear)
+static int sram2_clr_bits(struct r8152 *tp, u16 addr, u16 clear)
{
- sram2_write_w0w1(tp, addr, clear, 0);
+ return sram2_write_w0w1(tp, addr, clear, 0);
}
-static void r8152_mdio_clr_bit(struct r8152 *tp, u16 addr, u16 clear)
+static int r8152_mdio_clr_bit(struct r8152 *tp, u16 addr, u16 clear)
{
int data;
data = r8152_mdio_read(tp, addr);
- r8152_mdio_write(tp, addr, data & ~clear);
+ if (data < 0)
+ goto out;
+
+ data = r8152_mdio_write(tp, addr, data & ~clear);
+
+out:
+ return data;
}
-static void r8152_mdio_set_bit(struct r8152 *tp, u16 addr, u16 set)
+static int r8152_mdio_set_bit(struct r8152 *tp, u16 addr, u16 set)
{
int data;
data = r8152_mdio_read(tp, addr);
- r8152_mdio_write(tp, addr, data | set);
+ if (data < 0)
+ goto out;
+
+ data = r8152_mdio_write(tp, addr, data | set);
+
+out:
+ return data;
}
static int r8152_mdio_test_and_clr_bit(struct r8152 *tp, u16 addr, u16 clear)
{
- int data;
+ int data, ret;
- data = r8152_mdio_read(tp, addr);
- if (data & clear)
- r8152_mdio_write(tp, addr, data & ~clear);
+ ret = r8152_mdio_read(tp, addr);
+ if (ret < 0)
+ goto out;
+
+ data = ret;
+ if (data & clear) {
+ ret = r8152_mdio_write(tp, addr, data & ~clear);
+ if (ret < 0)
+ goto out;
+ }
+
+ ret = !!(data & clear);
- return data & clear;
+out:
+ return ret;
+}
+
+static int wait_tgphy_cmd_ready(struct r8152 *tp)
+{
+ u16 ocp_data;
+ int ret;
+
+ ret = read_poll_timeout(ocp_read_word, ocp_data,
+ test_bit(RTL8152_INACCESSIBLE, &tp->flags) ||
+ !(ocp_data & TGPHY_CMD_BUSY),
+ 2000, 20000, false, tp,
+ MCU_TYPE_USB, USB_TGPHY_CMD);
+
+ if (ret)
+ dev_err_ratelimited(&tp->intf->dev, "TGPHY cmd busy timeout\n");
+
+ return test_bit(RTL8152_INACCESSIBLE, &tp->flags) ? -ENODEV : ret;
+}
+
+static int rtl_tgphy_access(struct r8152 *tp, u16 addr, u16 *data, bool write)
+{
+ u16 cmd = 0;
+ int ret;
+
+ ret = wait_tgphy_cmd_ready(tp);
+ if (ret < 0)
+ goto out;
+
+ if (write) {
+ cmd |= TGPHY_CMD_WR;
+ ocp_write_word(tp, MCU_TYPE_USB, USB_TGPHY_DATA, *data);
+ }
+
+ ocp_write_word(tp, MCU_TYPE_USB, USB_TGPHY_ADDR, addr);
+
+ cmd |= TGPHY_CMD_BUSY;
+ ocp_write_word(tp, MCU_TYPE_USB, USB_TGPHY_CMD, cmd);
+
+ if (!write) {
+ ret = wait_tgphy_cmd_ready(tp);
+ if (ret < 0)
+ goto out;
+
+ *data = ocp_read_word(tp, MCU_TYPE_USB, USB_TGPHY_DATA);
+ }
+
+out:
+ /* A failed control transfer latches RTL8152_INACCESSIBLE */
+ if (!ret && test_bit(RTL8152_INACCESSIBLE, &tp->flags))
+ ret = -ENODEV;
+
+ return ret;
+}
+
+static int r8157_phy_read(struct r8152 *tp, u16 addr, u16 *data)
+{
+ return rtl_tgphy_access(tp, addr, data, false);
+}
+
+static int r8157_phy_write(struct r8152 *tp, u16 addr, u16 data)
+{
+ return rtl_tgphy_access(tp, addr, &data, true);
}
static int
@@ -4187,18 +4355,20 @@ static void r8153b_green_en(struct r8152 *tp, bool enable)
static u16 r8153_phy_status(struct r8152 *tp, u16 desired)
{
- u16 data;
+ u16 data = 0, val;
int i;
for (i = 0; i < 500; i++) {
- data = ocp_reg_read(tp, OCP_PHY_STATUS);
- data &= PHY_STAT_MASK;
- if (desired) {
- if (data == desired)
+ if (!ocp_reg_read(tp, OCP_PHY_STATUS, &val)) {
+ data = val & PHY_STAT_MASK;
+ if (desired) {
+ if (data == desired)
+ break;
+ } else if (data == PHY_STAT_LAN_ON ||
+ data == PHY_STAT_PWRDN ||
+ data == PHY_STAT_EXT_INIT) {
break;
- } else if (data == PHY_STAT_LAN_ON || data == PHY_STAT_PWRDN ||
- data == PHY_STAT_EXT_INIT) {
- break;
+ }
}
msleep(20);
@@ -4597,36 +4767,52 @@ static inline void rtl_reset_ocp_base(struct r8152 *tp)
static int rtl_phy_patch_request(struct r8152 *tp, bool request, bool wait)
{
u16 check;
- int i;
+ u16 ocp_data;
+ int i, ret;
if (request) {
- ocp_reg_set_bits(tp, OCP_PHY_PATCH_CMD, PATCH_REQUEST);
+ ret = ocp_reg_set_bits(tp, OCP_PHY_PATCH_CMD, PATCH_REQUEST);
check = 0;
} else {
- ocp_reg_clr_bits(tp, OCP_PHY_PATCH_CMD, PATCH_REQUEST);
+ ret = ocp_reg_clr_bits(tp, OCP_PHY_PATCH_CMD, PATCH_REQUEST);
check = PATCH_READY;
}
- for (i = 0; wait && i < 5000; i++) {
- u32 ocp_data;
+ if (ret < 0)
+ return ret;
- if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
- return -ENODEV;
+ for (i = 0; wait && i < 5000; i++) {
+ if (test_bit(RTL8152_INACCESSIBLE, &tp->flags)) {
+ ret = -ENODEV;
+ goto err;
+ }
usleep_range(1000, 2000);
- ocp_data = ocp_reg_read(tp, OCP_PHY_PATCH_STAT);
- if ((ocp_data & PATCH_READY) ^ check)
+ ret = ocp_reg_read(tp, OCP_PHY_PATCH_STAT, &ocp_data);
+ if (ret < 0)
+ goto err;
+ else if ((ocp_data & PATCH_READY) ^ check)
break;
}
- if (request && wait &&
- !(ocp_reg_read(tp, OCP_PHY_PATCH_STAT) & PATCH_READY)) {
- dev_err(&tp->intf->dev, "PHY patch request fail\n");
- rtl_phy_patch_request(tp, false, false);
- return -ETIME;
- } else {
- return 0;
+ if (request && wait) {
+ ret = ocp_reg_read(tp, OCP_PHY_PATCH_STAT, &ocp_data);
+ if (ret < 0) {
+ goto err;
+ } else if (!(ocp_data & PATCH_READY)) {
+ dev_err(&tp->intf->dev, "PHY patch request fail\n");
+ ret = -ETIME;
+ goto err;
+ }
}
+
+ return 0;
+
+err:
+ if (request)
+ rtl_phy_patch_request(tp, false, false);
+
+ return ret;
}
static void rtl_patch_key_set(struct r8152 *tp, u16 key_addr, u16 patch_key)
@@ -4646,8 +4832,11 @@ static void rtl_patch_key_set(struct r8152 *tp, u16 key_addr, u16 patch_key)
static int
rtl_pre_ram_code(struct r8152 *tp, u16 key_addr, u16 patch_key, bool wait)
{
- if (rtl_phy_patch_request(tp, true, wait))
- return -ETIME;
+ int ret;
+
+ ret = rtl_phy_patch_request(tp, true, wait);
+ if (ret)
+ return ret;
rtl_patch_key_set(tp, key_addr, patch_key);
@@ -5341,10 +5530,14 @@ static void rtl_ram_code_speed_up(struct r8152 *tp, struct fw_phy_speed_up *phy,
{
u32 len;
u8 *data;
+ u16 ver;
rtl_reset_ocp_base(tp);
- if (sram_read(tp, SRAM_GPHY_FW_VER) >= __le16_to_cpu(phy->version)) {
+ if (sram_read(tp, SRAM_GPHY_FW_VER, &ver) < 0)
+ return;
+
+ if (ver >= __le16_to_cpu(phy->version)) {
dev_dbg(&tp->intf->dev, "PHY firmware has been the newest\n");
return;
}
@@ -5391,7 +5584,8 @@ static void rtl_ram_code_speed_up(struct r8152 *tp, struct fw_phy_speed_up *phy,
rtl_phy_patch_request(tp, false, wait);
- if (sram_read(tp, SRAM_GPHY_FW_VER) == __le16_to_cpu(phy->version))
+ if (sram_read(tp, SRAM_GPHY_FW_VER, &ver) >= 0 &&
+ ver == __le16_to_cpu(phy->version))
dev_dbg(&tp->intf->dev, "successfully applied %s\n", phy->info);
else
dev_err(&tp->intf->dev, "ram code speedup mode fail\n");
@@ -5399,14 +5593,17 @@ static void rtl_ram_code_speed_up(struct r8152 *tp, struct fw_phy_speed_up *phy,
static int rtl8152_fw_phy_ver(struct r8152 *tp, struct fw_phy_ver *phy_ver)
{
- u16 ver_addr, ver;
+ u16 ver_addr, ver, cur_ver;
ver_addr = __le16_to_cpu(phy_ver->ver.addr);
ver = __le16_to_cpu(phy_ver->ver.data);
rtl_reset_ocp_base(tp);
- if (sram_read(tp, ver_addr) >= ver) {
+ if (sram_read(tp, ver_addr, &cur_ver) < 0)
+ return 0;
+
+ if (cur_ver >= ver) {
dev_dbg(&tp->intf->dev, "PHY firmware has been the newest\n");
return 0;
}
@@ -5425,7 +5622,8 @@ static void rtl8152_fw_phy_fixup(struct r8152 *tp, struct fw_phy_fixup *fix)
rtl_reset_ocp_base(tp);
addr = __le16_to_cpu(fix->setting.addr);
- data = ocp_reg_read(tp, addr);
+ if (ocp_reg_read(tp, addr, &data) < 0)
+ return;
switch (__le16_to_cpu(fix->bit_cmd)) {
case FW_FIXUP_AND:
@@ -5729,10 +5927,10 @@ static inline void r8152_mmd_indirect(struct r8152 *tp, u16 dev, u16 reg)
static u16 r8152_mmd_read(struct r8152 *tp, u16 dev, u16 reg)
{
- u16 data;
+ u16 data = 0;
r8152_mmd_indirect(tp, dev, reg);
- data = ocp_reg_read(tp, OCP_EEE_DATA);
+ ocp_reg_read(tp, OCP_EEE_DATA, &data);
ocp_reg_write(tp, OCP_EEE_AR, 0x0000);
return data;
@@ -5797,7 +5995,8 @@ static void r8156_eee_en(struct r8152 *tp, bool enable)
r8153_eee_en(tp, enable);
- config = ocp_reg_read(tp, OCP_EEE_ADV2);
+ if (ocp_reg_read(tp, OCP_EEE_ADV2, &config) < 0)
+ return;
if (enable && (tp->eee_adv2 & MDIO_EEE_2_5GT))
config |= MDIO_EEE_2_5GT;
@@ -6351,8 +6550,8 @@ static void r8153b_hw_phy_cfg(struct r8152 *tp)
* rg_saw_cnt = OCP reg 0xC426 Bit[13:0]
* swr_cnt_1ms_ini = 16000000 / rg_saw_cnt
*/
- ocp_data = ocp_reg_read(tp, 0xc426);
- ocp_data &= 0x3fff;
+ ocp_reg_read(tp, 0xc426, &data);
+ ocp_data = data & 0x3fff;
if (ocp_data) {
u32 swr_cnt_1ms_ini;
@@ -6704,7 +6903,11 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u32 speed, u8 duplex,
if (!advertising)
return -EINVAL;
- orig = r8152_mdio_read(tp, MII_ADVERTISE);
+ ret = r8152_mdio_read(tp, MII_ADVERTISE);
+ if (ret < 0)
+ goto out;
+
+ orig = ret;
new1 = orig & ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
ADVERTISE_100HALF | ADVERTISE_100FULL);
if (advertising & RTL_ADVERTISED_10_HALF) {
@@ -6726,12 +6929,19 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u32 speed, u8 duplex,
}
if (orig != new1) {
- r8152_mdio_write(tp, MII_ADVERTISE, new1);
+ ret = r8152_mdio_write(tp, MII_ADVERTISE, new1);
+ if (ret < 0)
+ goto out;
+
tp->mii.advertising = new1;
}
if (tp->mii.supports_gmii) {
- orig = r8152_mdio_read(tp, MII_CTRL1000);
+ ret = r8152_mdio_read(tp, MII_CTRL1000);
+ if (ret < 0)
+ goto out;
+
+ orig = ret;
new1 = orig & ~(ADVERTISE_1000FULL |
ADVERTISE_1000HALF);
@@ -6740,12 +6950,18 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u32 speed, u8 duplex,
tp->ups_info.speed_duplex = NWAY_1000M_FULL;
}
- if (orig != new1)
- r8152_mdio_write(tp, MII_CTRL1000, new1);
+ if (orig != new1) {
+ ret = r8152_mdio_write(tp, MII_CTRL1000, new1);
+ if (ret < 0)
+ goto out;
+ }
}
if (tp->support_2500full || tp->support_5000full || tp->support_10000full) {
- orig = ocp_reg_read(tp, OCP_10GBT_CTRL);
+ ret = ocp_reg_read(tp, OCP_10GBT_CTRL, &orig);
+ if (ret < 0)
+ goto out;
+
new1 = orig & ~(MDIO_AN_10GBT_CTRL_ADV2_5G | MDIO_AN_10GBT_CTRL_ADV5G
| MDIO_AN_10GBT_CTRL_ADV10G);
@@ -6764,8 +6980,11 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u32 speed, u8 duplex,
tp->ups_info.speed_duplex = NWAY_10000M_FULL;
}
- if (orig != new1)
- ocp_reg_write(tp, OCP_10GBT_CTRL, new1);
+ if (orig != new1) {
+ ret = ocp_reg_write(tp, OCP_10GBT_CTRL, new1);
+ if (ret < 0)
+ goto out;
+ }
}
bmcr = BMCR_ANENABLE | BMCR_ANRESTART;
@@ -6776,20 +6995,26 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u32 speed, u8 duplex,
if (test_and_clear_bit(PHY_RESET, &tp->flags))
bmcr |= BMCR_RESET;
- r8152_mdio_write(tp, MII_BMCR, bmcr);
+ ret = r8152_mdio_write(tp, MII_BMCR, bmcr);
+ if (ret < 0) {
+ if (bmcr & BMCR_RESET)
+ set_bit(PHY_RESET, &tp->flags);
+ goto out;
+ }
if (bmcr & BMCR_RESET) {
int i;
for (i = 0; i < 50; i++) {
msleep(20);
- if ((r8152_mdio_read(tp, MII_BMCR) & BMCR_RESET) == 0)
+ ret = r8152_mdio_read(tp, MII_BMCR);
+ if (ret < 0 || !(ret & BMCR_RESET))
break;
}
}
out:
- return ret;
+ return ret < 0 ? ret : 0;
}
static void rtl8152_up(struct r8152 *tp)
@@ -7205,7 +7430,12 @@ static bool rtl8152_in_nway(struct r8152 *tp)
static bool rtl8153_in_nway(struct r8152 *tp)
{
- u16 phy_state = ocp_reg_read(tp, OCP_PHY_STATE) & 0xff;
+ u16 phy_state;
+
+ if (ocp_reg_read(tp, OCP_PHY_STATE, &phy_state) < 0)
+ return false;
+
+ phy_state &= 0xff;
if (phy_state == TXDIS_STATE || phy_state == ABD_STATE)
return false;
@@ -7221,7 +7451,9 @@ static void r8156_mdio_force_mode(struct r8152 *tp)
* 0: MDIO force mode
* 1: MMD force mode
*/
- data = ocp_reg_read(tp, 0xa5b4);
+ if (ocp_reg_read(tp, 0xa5b4, &data) < 0)
+ return;
+
if (data & BIT(15)) {
data &= ~BIT(15);
ocp_reg_write(tp, 0xa5b4, data);
@@ -7861,19 +8093,20 @@ static void r8156_hw_phy_cfg(struct r8152 *tp)
ocp_reg_clr_bits(tp, 0xa86a, BIT(0));
/* MDI SWAP */
+ ocp_reg_read(tp, 0xd068, &data);
if ((ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CFG) & MID_REVERSE) &&
- (ocp_reg_read(tp, 0xd068) & BIT(1))) {
+ (data & BIT(1))) {
u16 swap_a, swap_b;
- data = ocp_reg_read(tp, 0xd068);
+ ocp_reg_read(tp, 0xd068, &data);
data &= ~0x1f;
data |= 0x1; /* p0 */
ocp_reg_write(tp, 0xd068, data);
- swap_a = ocp_reg_read(tp, 0xd06a);
+ ocp_reg_read(tp, 0xd06a, &swap_a);
data &= ~0x18;
data |= 0x18; /* p3 */
ocp_reg_write(tp, 0xd068, data);
- swap_b = ocp_reg_read(tp, 0xd06a);
+ ocp_reg_read(tp, 0xd06a, &swap_b);
data &= ~0x18; /* p0 */
ocp_reg_write(tp, 0xd068, data);
ocp_reg_write(tp, 0xd06a,
@@ -7885,11 +8118,11 @@ static void r8156_hw_phy_cfg(struct r8152 *tp)
data &= ~0x18;
data |= 0x08; /* p1 */
ocp_reg_write(tp, 0xd068, data);
- swap_a = ocp_reg_read(tp, 0xd06a);
+ ocp_reg_read(tp, 0xd06a, &swap_a);
data &= ~0x18;
data |= 0x10; /* p2 */
ocp_reg_write(tp, 0xd068, data);
- swap_b = ocp_reg_read(tp, 0xd06a);
+ ocp_reg_read(tp, 0xd06a, &swap_b);
data &= ~0x18;
data |= 0x08; /* p1 */
ocp_reg_write(tp, 0xd068, data);
@@ -7900,16 +8133,16 @@ static void r8156_hw_phy_cfg(struct r8152 *tp)
ocp_reg_write(tp, 0xd068, data);
ocp_reg_write(tp, 0xd06a,
(swap_b & ~0x7ff) | (swap_a & 0x7ff));
- swap_a = ocp_reg_read(tp, 0xbd5a);
- swap_b = ocp_reg_read(tp, 0xbd5c);
+ ocp_reg_read(tp, 0xbd5a, &swap_a);
+ ocp_reg_read(tp, 0xbd5c, &swap_b);
ocp_reg_write(tp, 0xbd5a, (swap_a & ~0x1f1f) |
((swap_b & 0x1f) << 8) |
((swap_b >> 8) & 0x1f));
ocp_reg_write(tp, 0xbd5c, (swap_b & ~0x1f1f) |
((swap_a & 0x1f) << 8) |
((swap_a >> 8) & 0x1f));
- swap_a = ocp_reg_read(tp, 0xbc18);
- swap_b = ocp_reg_read(tp, 0xbc1a);
+ ocp_reg_read(tp, 0xbc18, &swap_a);
+ ocp_reg_read(tp, 0xbc1a, &swap_b);
ocp_reg_write(tp, 0xbc18, (swap_a & ~0x1f1f) |
((swap_b & 0x1f) << 8) |
((swap_b >> 8) & 0x1f));
@@ -9388,8 +9621,16 @@ int rtl8152_get_link_ksettings(struct net_device *netdev,
cmd->link_modes.supported, tp->support_10000full);
if (tp->support_2500full || tp->support_5000full || tp->support_10000full) {
- u16 ocp_10gbt_ctrl = ocp_reg_read(tp, OCP_10GBT_CTRL);
- u16 ocp_10gbt_stat = ocp_reg_read(tp, OCP_10GBT_STAT);
+ u16 ocp_10gbt_ctrl;
+ u16 ocp_10gbt_stat;
+
+ ret = ocp_reg_read(tp, OCP_10GBT_CTRL, &ocp_10gbt_ctrl);
+ if (ret < 0)
+ goto out_unlock;
+
+ ret = ocp_reg_read(tp, OCP_10GBT_STAT, &ocp_10gbt_stat);
+ if (ret < 0)
+ goto out_unlock;
if (tp->support_2500full) {
linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
@@ -9431,12 +9672,13 @@ int rtl8152_get_link_ksettings(struct net_device *netdev,
}
}
+out_unlock:
mutex_unlock(&tp->control);
usb_autopm_put_interface(tp->intf);
out:
- return ret;
+ return ret < 0 ? ret : 0;
}
static int rtl8152_set_link_ksettings(struct net_device *dev,
@@ -9617,21 +9859,37 @@ static int r8153_get_eee(struct r8152 *tp, struct ethtool_keee *eee)
__ETHTOOL_DECLARE_LINK_MODE_MASK(common) = {};
u16 speed = rtl8152_get_speed(tp);
u16 val;
+ int ret;
+
+ ret = ocp_reg_read(tp, OCP_EEE_ABLE, &val);
+ if (ret < 0)
+ goto out;
- val = ocp_reg_read(tp, OCP_EEE_ABLE);
mii_eee_cap1_mod_linkmode_t(eee->supported, val);
- val = ocp_reg_read(tp, OCP_EEE_ADV);
+ ret = ocp_reg_read(tp, OCP_EEE_ADV, &val);
+ if (ret < 0)
+ goto out;
+
mii_eee_cap1_mod_linkmode_t(eee->advertised, val);
- val = ocp_reg_read(tp, OCP_EEE_LPABLE);
+ ret = ocp_reg_read(tp, OCP_EEE_LPABLE, &val);
+ if (ret < 0)
+ goto out;
+
mii_eee_cap1_mod_linkmode_t(eee->lp_advertised, val);
if (tp->support_2500full || tp->support_5000full) {
- val = ocp_reg_read(tp, OCP_EEE_ADV2);
+ ret = ocp_reg_read(tp, OCP_EEE_ADV2, &val);
+ if (ret < 0)
+ goto out;
+
mii_eee_cap2_mod_linkmode_adv_t(eee->advertised, val);
- val = ocp_reg_read(tp, OCP_EEE_LPABLE2);
+ ret = ocp_reg_read(tp, OCP_EEE_LPABLE2, &val);
+ if (ret < 0)
+ goto out;
+
mii_eee_cap2_mod_linkmode_adv_t(eee->lp_advertised, val);
}
@@ -9667,7 +9925,8 @@ static int r8153_get_eee(struct r8152 *tp, struct ethtool_keee *eee)
linkmode_and(common, common, eee->lp_advertised);
eee->eee_active = !linkmode_empty(common);
- return 0;
+out:
+ return ret < 0 ? ret : 0;
}
static int
@@ -9907,7 +10166,7 @@ static int rtl8152_set_ringparam(struct net_device *netdev,
static void rtl8152_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause)
{
struct r8152 *tp = netdev_priv(netdev);
- u16 bmcr, lcladv, rmtadv;
+ int bmcr, lcladv, rmtadv;
u8 cap;
if (usb_autopm_get_interface(tp->intf) < 0)
@@ -9923,7 +10182,10 @@ static void rtl8152_get_pauseparam(struct net_device *netdev, struct ethtool_pau
usb_autopm_put_interface(tp->intf);
- if (!(bmcr & BMCR_ANENABLE)) {
+ /* Without a readable PHY, or with autoneg off, there is no flow
+ * control to report.
+ */
+ if (bmcr < 0 || lcladv < 0 || rmtadv < 0 || !(bmcr & BMCR_ANENABLE)) {
pause->autoneg = 0;
pause->rx_pause = 0;
pause->tx_pause = 0;
@@ -9954,7 +10216,11 @@ static int rtl8152_set_pauseparam(struct net_device *netdev, struct ethtool_paus
mutex_lock(&tp->control);
- if (pause->autoneg && !(r8152_mdio_read(tp, MII_BMCR) & BMCR_ANENABLE)) {
+ ret = r8152_mdio_read(tp, MII_BMCR);
+ if (ret < 0)
+ goto out;
+
+ if (pause->autoneg && !(ret & BMCR_ANENABLE)) {
ret = -EINVAL;
goto out;
}
@@ -9965,16 +10231,20 @@ static int rtl8152_set_pauseparam(struct net_device *netdev, struct ethtool_paus
if (pause->tx_pause)
cap |= FLOW_CTRL_TX;
- old = r8152_mdio_read(tp, MII_ADVERTISE);
+ ret = r8152_mdio_read(tp, MII_ADVERTISE);
+ if (ret < 0)
+ goto out;
+
+ old = ret;
new1 = (old & ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM)) | mii_advertise_flowctrl(cap);
if (old != new1)
- r8152_mdio_write(tp, MII_ADVERTISE, new1);
+ ret = r8152_mdio_write(tp, MII_ADVERTISE, new1);
out:
mutex_unlock(&tp->control);
usb_autopm_put_interface(tp->intf);
- return ret;
+ return ret < 0 ? ret : 0;
}
static const struct ethtool_ops ops = {
@@ -10008,7 +10278,7 @@ static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
{
struct r8152 *tp = netdev_priv(netdev);
struct mii_ioctl_data *data = if_mii(rq);
- int res;
+ int res, val;
if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
return -ENODEV;
@@ -10024,7 +10294,11 @@ static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
case SIOCGMIIREG:
mutex_lock(&tp->control);
- data->val_out = r8152_mdio_read(tp, data->reg_num);
+ val = r8152_mdio_read(tp, data->reg_num);
+ if (val < 0)
+ res = val;
+ else
+ data->val_out = val;
mutex_unlock(&tp->control);
break;
@@ -10034,7 +10308,7 @@ static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
break;
}
mutex_lock(&tp->control);
- r8152_mdio_write(tp, data->reg_num, data->val_in);
+ res = r8152_mdio_write(tp, data->reg_num, data->val_in);
mutex_unlock(&tp->control);
break;
@@ -10197,6 +10471,8 @@ static int rtl_ops_init(struct r8152 *tp)
ops->in_nway = rtl8152_in_nway;
ops->hw_phy_cfg = r8152b_hw_phy_cfg;
ops->autosuspend_en = rtl_runtime_suspend_enable;
+ ops->phy_read = r8152_phy_read;
+ ops->phy_write = r8152_phy_write;
tp->rx_buf_sz = 16 * 1024;
tp->eee_en = true;
tp->eee_adv = MDIO_EEE_100TX;
@@ -10219,6 +10495,8 @@ static int rtl_ops_init(struct r8152 *tp)
ops->hw_phy_cfg = r8153_hw_phy_cfg;
ops->autosuspend_en = rtl8153_runtime_enable;
ops->change_mtu = rtl8153_change_mtu;
+ ops->phy_read = r8152_phy_read;
+ ops->phy_write = r8152_phy_write;
if (tp->udev->speed < USB_SPEED_SUPER)
tp->rx_buf_sz = 16 * 1024;
else
@@ -10242,6 +10520,8 @@ static int rtl_ops_init(struct r8152 *tp)
ops->hw_phy_cfg = r8153b_hw_phy_cfg;
ops->autosuspend_en = rtl8153b_runtime_enable;
ops->change_mtu = rtl8153_change_mtu;
+ ops->phy_read = r8152_phy_read;
+ ops->phy_write = r8152_phy_write;
tp->rx_buf_sz = 32 * 1024;
tp->eee_en = true;
tp->eee_adv = MDIO_EEE_1000T | MDIO_EEE_100TX;
@@ -10266,6 +10546,8 @@ static int rtl_ops_init(struct r8152 *tp)
ops->hw_phy_cfg = r8156_hw_phy_cfg;
ops->autosuspend_en = rtl8156_runtime_enable;
ops->change_mtu = rtl8156_change_mtu;
+ ops->phy_read = r8152_phy_read;
+ ops->phy_write = r8152_phy_write;
tp->rx_buf_sz = 48 * 1024;
tp->support_2500full = 1;
r8152_desc_init(tp);
@@ -10291,6 +10573,8 @@ static int rtl_ops_init(struct r8152 *tp)
ops->hw_phy_cfg = r8156b_hw_phy_cfg;
ops->autosuspend_en = rtl8156_runtime_enable;
ops->change_mtu = rtl8156_change_mtu;
+ ops->phy_read = r8152_phy_read;
+ ops->phy_write = r8152_phy_write;
tp->rx_buf_sz = 48 * 1024;
r8152_desc_init(tp);
break;
@@ -10308,6 +10592,8 @@ static int rtl_ops_init(struct r8152 *tp)
ops->hw_phy_cfg = r8153c_hw_phy_cfg;
ops->autosuspend_en = rtl8153c_runtime_enable;
ops->change_mtu = rtl8153c_change_mtu;
+ ops->phy_read = r8152_phy_read;
+ ops->phy_write = r8152_phy_write;
tp->rx_buf_sz = 32 * 1024;
tp->eee_en = true;
tp->eee_adv = MDIO_EEE_1000T | MDIO_EEE_100TX;
@@ -10330,6 +10616,8 @@ static int rtl_ops_init(struct r8152 *tp)
ops->hw_phy_cfg = r8157_hw_phy_cfg;
ops->autosuspend_en = rtl8157_runtime_enable;
ops->change_mtu = rtl8157_change_mtu;
+ ops->phy_read = r8157_phy_read;
+ ops->phy_write = r8157_phy_write;
tp->rx_buf_sz = 32 * 1024;
tp->support_2500full = 1;
tp->support_5000full = 1;
@@ -10353,6 +10641,8 @@ static int rtl_ops_init(struct r8152 *tp)
ops->hw_phy_cfg = r8159_hw_phy_cfg;
ops->autosuspend_en = rtl8157_runtime_enable;
ops->change_mtu = rtl8157_change_mtu;
+ ops->phy_read = r8157_phy_read;
+ ops->phy_write = r8157_phy_write;
tp->rx_buf_sz = 48 * 1024;
tp->support_2500full = 1;
tp->support_5000full = 1;
--
2.34.1
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH net-next v8 11/11] r8152: enable UPS for RTL8157 and RTL8159 QFN68
2026-11-10 3:24 [PATCH net-next v8 00/11] r8152: refactor and extend RTL8157/8159 support Chih Kai Hsu
` (9 preceding siblings ...)
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 ` Chih Kai Hsu
2026-11-10 5:04 ` [PATCH net-next v8 00/11] r8152: refactor and extend RTL8157/8159 support netdev-bot+sinfo
11 siblings, 0 replies; 13+ messages in thread
From: Chih Kai Hsu @ 2026-11-10 3:24 UTC (permalink / raw)
To: davem, kuba
Cc: netdev, nic_swsd, linux-kernel, linux-usb, edumazet, bjorn,
pabeni, hsu.chih.kai, andrew+netdev, mail
RTL8157 and RTL8159 QFN68 support UPS, but rtl8157_runtime_enable()
never toggled it on runtime suspend/resume, and r8156_ups_flags()
used the older per-chip EEE/lite_mode encoding instead of the
per-speed EEE flags their UPS firmware expects. RTL8159 QFN100 does
not support UPS.
Add r8157_ups_en(), mirroring r8156_ups_en(), and call it from
rtl8157_runtime_enable() for VER_16/QFN68 only; QFN100 keeps its
existing no-UPS behaviour there. Use r8157_ups_en(tp, false) in
r8157_init() in place of r8156_ups_en(tp, false).
Extend r8156_ups_flags() with per-speed EEE flags
(UPS_FLAGS_EN_100M_EEE/1000M_EEE/2500M_EEE/5000M_EEE/10G_EEE) and
skip the lite_mode bits[6:5] encoding for VER_16/QFN68. Add
ups_flags_speed() entries 10 and 11 for NWAY_5000M_FULL and
NWAY_10000M_FULL, previously unmapped.
Add the USB_FW_USB_VER register (0xcfd7), used by the new
r8157_ups_en() disable path.
If the backup-restore wait in r8157_ups_en() times out, it marks the
device inaccessible and logs, without queuing a reset, as
r8157_init() does for the same wait. During runtime resume the
interface then stays unusable until a replug or an unrelated reset,
since r8157_ups_en() returns void and the error is not passed back.
Recovery for these timeouts is left to a follow-up series.
Signed-off-by: Chih Kai Hsu <hsu.chih.kai@realtek.com>
---
drivers/net/usb/r8152.c | 131 ++++++++++++++++++++++++++++++++++++----
1 file changed, 120 insertions(+), 11 deletions(-)
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 703ec5483778b..9c7031f938bc2 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -132,6 +132,7 @@
#define USB_BURST_SIZE 0xcfc0
#define USB_FW_FIX_EN0 0xcfca
#define USB_FW_FIX_EN1 0xcfcc
+#define USB_FW_USB_VER 0xcfd7
#define USB_LPM_CONFIG 0xcfd8
#define USB_ECM_OPTION 0xcfee
#define USB_CSTMR 0xcfef /* RTL8153A */
@@ -619,6 +620,11 @@
#define UPS_FLAGS_250M_CKDIV BIT(2)
#define UPS_FLAGS_EN_ALDPS BIT(3)
#define UPS_FLAGS_CTAP_SHORT_DIS BIT(4)
+#define UPS_FLAGS_EN_100M_EEE BIT(9)
+#define UPS_FLAGS_EN_1000M_EEE BIT(10)
+#define UPS_FLAGS_EN_2500M_EEE BIT(11)
+#define UPS_FLAGS_EN_5000M_EEE BIT(12)
+#define UPS_FLAGS_EN_10G_EEE BIT(13)
#define UPS_FLAGS_SPEED_MASK (0xf << 16)
#define ups_flags_speed(x) ((x) << 16)
#define UPS_FLAGS_EN_EEE BIT(20)
@@ -4256,8 +4262,27 @@ static void r8156_ups_flags(struct r8152 *tp)
if (tp->ups_info.aldps)
ups_flags |= UPS_FLAGS_EN_ALDPS;
- if (tp->ups_info.eee)
- ups_flags |= UPS_FLAGS_EN_EEE;
+ if (tp->ups_info.eee) {
+ switch (tp->version) {
+ case RTL_VER_17_QFN68:
+ if (tp->eee_adv & MDIO_EEE_10GT)
+ ups_flags |= UPS_FLAGS_EN_10G_EEE;
+ fallthrough;
+ case RTL_VER_16:
+ if (tp->eee_adv & MDIO_EEE_100TX)
+ ups_flags |= UPS_FLAGS_EN_100M_EEE;
+ if (tp->eee_adv & MDIO_EEE_1000T)
+ ups_flags |= UPS_FLAGS_EN_1000M_EEE;
+ if (tp->eee_adv2 & MDIO_EEE_2_5GT)
+ ups_flags |= UPS_FLAGS_EN_2500M_EEE;
+ if (tp->eee_adv2 & MDIO_EEE_5GT)
+ ups_flags |= UPS_FLAGS_EN_5000M_EEE;
+ break;
+ default:
+ ups_flags |= UPS_FLAGS_EN_EEE;
+ break;
+ }
+ }
if (tp->ups_info.flow_control)
ups_flags |= UPS_FLAGS_EN_FLOW_CTR;
@@ -4308,20 +4333,33 @@ static void r8156_ups_flags(struct r8152 *tp)
case NWAY_2500M_FULL:
ups_flags |= ups_flags_speed(9);
break;
+ case NWAY_5000M_FULL:
+ ups_flags |= ups_flags_speed(10);
+ break;
+ case NWAY_10000M_FULL:
+ ups_flags |= ups_flags_speed(11);
+ break;
default:
break;
}
- switch (tp->ups_info.lite_mode) {
- case 1:
- ups_flags |= 0 << 5;
- break;
- case 2:
- ups_flags |= 2 << 5;
+ switch (tp->version) {
+ case RTL_VER_16:
+ case RTL_VER_17_QFN68:
break;
- case 0:
default:
- ups_flags |= 1 << 5;
+ switch (tp->ups_info.lite_mode) {
+ case 1:
+ ups_flags |= 0 << 5;
+ break;
+ case 2:
+ ups_flags |= 2 << 5;
+ break;
+ case 0:
+ default:
+ ups_flags |= 1 << 5;
+ break;
+ }
break;
}
@@ -4496,6 +4534,58 @@ static void r8156_ups_en(struct r8152 *tp, bool enable)
}
}
+static void r8157_ups_en(struct r8152 *tp, bool enable)
+{
+ u32 ocp_data;
+ int ret;
+
+ if (enable) {
+ r8156_ups_flags(tp);
+
+ ocp_byte_set_bits(tp, MCU_TYPE_USB, USB_POWER_CUT,
+ UPS_EN | USP_PREWAKE | PHASE2_EN);
+
+ ocp_byte_set_bits(tp, MCU_TYPE_USB, USB_MISC_2,
+ UPS_FORCE_PWR_DOWN);
+ } else {
+ ocp_byte_clr_bits(tp, MCU_TYPE_USB, USB_POWER_CUT,
+ UPS_EN | USP_PREWAKE);
+
+ ocp_byte_clr_bits(tp, MCU_TYPE_USB, USB_MISC_2,
+ UPS_FORCE_PWR_DOWN);
+
+ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0);
+ if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
+ return;
+
+ if (ocp_data & PCUT_STATUS) {
+ ret = read_poll_timeout(ocp_read_word, ocp_data,
+ test_bit(RTL8152_INACCESSIBLE,
+ &tp->flags) ||
+ (ocp_data & BACKUP_RESTRORE),
+ 200, 20000, false, tp,
+ MCU_TYPE_USB, USB_GPHY_CTRL);
+ if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
+ return;
+
+ if (ret) {
+ rtl_set_inaccessible(tp);
+ dev_err(&tp->intf->dev,
+ "backup-restore timed out\n");
+ return;
+ }
+
+ /* clear USB fw_ver_reg */
+ ocp_write_byte(tp, MCU_TYPE_USB, USB_FW_USB_VER, 0);
+
+ tp->rtl_ops.hw_phy_cfg(tp);
+
+ rtl8152_set_speed(tp, tp->autoneg, tp->speed,
+ tp->duplex, tp->advertising);
+ }
+ }
+}
+
static void r8153_power_cut_en(struct r8152 *tp, bool enable)
{
if (enable)
@@ -4654,9 +4744,28 @@ static void rtl8157_runtime_enable(struct r8152 *tp, bool enable)
r8153b_u1u2en(tp, false);
r8157_u2p3en(tp, false);
rtl_runtime_suspend_enable(tp, true);
+
+ switch (tp->version) {
+ case RTL_VER_16:
+ case RTL_VER_17_QFN68:
+ r8157_ups_en(tp, true);
+ break;
+ default:
+ break;
+ }
} else {
r8153_queue_wake(tp, false);
rtl_runtime_suspend_enable(tp, false);
+
+ switch (tp->version) {
+ case RTL_VER_16:
+ case RTL_VER_17_QFN68:
+ r8157_ups_en(tp, false);
+ break;
+ default:
+ break;
+ }
+
r8157_u2p3en(tp, true);
if (tp->udev->speed >= USB_SPEED_SUPER)
r8153b_u1u2en(tp, true);
@@ -9120,7 +9229,7 @@ static void r8157_init(struct r8152 *tp)
ocp_write_word(tp, MCU_TYPE_USB, USB_U1U2_TIMER, 500);
r8157_power_cut_en(tp, false);
- r8156_ups_en(tp, false);
+ r8157_ups_en(tp, false);
r8153_queue_wake(tp, false);
rtl_runtime_suspend_enable(tp, false);
--
2.34.1
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH net-next v8 00/11] r8152: refactor and extend RTL8157/8159 support
2026-11-10 3:24 [PATCH net-next v8 00/11] r8152: refactor and extend RTL8157/8159 support Chih Kai Hsu
` (10 preceding siblings ...)
2026-11-10 3:24 ` [PATCH net-next v8 11/11] r8152: enable UPS for RTL8157 and RTL8159 QFN68 Chih Kai Hsu
@ 2026-11-10 5:04 ` netdev-bot+sinfo
11 siblings, 0 replies; 13+ messages in thread
From: netdev-bot+sinfo @ 2026-11-10 5:04 UTC (permalink / raw)
To: Chih Kai Hsu
Cc: davem, kuba, netdev, nic_swsd, linux-kernel, linux-usb, edumazet,
bjorn, pabeni, andrew+netdev, mail
Hi!
This is an automated message. This series looks like a fix, but its
commit messages seem to be missing some information:
- Whether the issue was actually triggered, or is only theoretical
(e.g. found by code inspection). If it was triggered please include
the symptoms, like the stack trace or error messages.
Please do not repost the series just to address the above. Instead,
reply to this email with the missing information, so that reviewers
can take it into account. If the series needs another revision for
other reasons, please include the information in the commit messages
then.
The evaluation is done by an LLM so it may be wrong, if you think
that is the case please reply and explain.
^ permalink raw reply [flat|nested] 13+ messages in thread