Linux USB
 help / color / mirror / Atom feed
* r8152: RTL8153 never runtime suspends with link up on a network with broadcast traffic
@ 2026-11-11  0:52 Paul Menzel
  2026-11-12  0:53 ` sashiko-bot
  0 siblings, 1 reply; 2+ messages in thread
From: Paul Menzel @ 2026-11-11  0:52 UTC (permalink / raw)
  To: Hayes Wang; +Cc: Chih Kai Hsu, Birger Koblitz, netdev, linux-usb

[-- Attachment #1: Type: text/plain, Size: 4034 bytes --]

Dear Hayes, dear Linux folks,


On a Dell XPS 13 9310 with a VIA Labs USB-C hub plugged in that has an 
RTL8153 (0bda:8153, bcdDevice 30.00, firmware rtl8153a-4 v3 06/12/25), 
the adapter never runtime suspends while the link is up, even with 
power/control set to auto. The hub and the Thunderbolt xHCI controller 
00:0d.0 therefore stay in D0, and the package does not go deeper than 
PC8. I would like to ask how you would want this solved before sending a 
patch.

AI disclaimer: claude-fable-5.2 analyzed and measured this on the laptop 
and drafted this message; I reviewed it.

With Linux 7.3.3 (Debian 7.3.3-1), link up at 1000 Mb/s, 
power/control=auto and autosuspend_delay_ms=2000, 60 s apart:

     2-1.1.3: active susp=0 act=140886
     2-1.1.3: active susp=0 act=201150

     $ sudo turbostat --quiet --Summary --show 
Pkg%pc2,Pkg%pc3,Pkg%pc8,Pkg%pc9,Pk%pc10,SYS%LPI,PkgWatt --interval 30 
--num_iterations 1
     Pkg%pc2 Pkg%pc3 Pkg%pc8 Pkg%pc9 Pk%pc10 SYS%LPI PkgWatt
       14.26    9.19   71.33    0.00    0.00    0.00    0.84

The cause is traffic that is not addressed to the station. In a 30 s 
capture of inbound frames on our institute network, 816 of 824 frames 
are broadcast (688, mostly ARP) or multicast (128), and 7 are addressed 
to the station. read_bulk_callback() calls usb_mark_last_busy() for 
every completed receive URB, so the autosuspend delay never elapses. If 
the device did suspend, rtl_runtime_suspend_enable() arms WAKE_ANY, so 
the next broadcast frame would wake it again.

As an experiment, I added a module parameter (patch attached, against 
Linus’ master fa4ad798f6f6; tested as an out-of-tree build of the v7.3.3 
driver). When set, only frames with a unicast destination address call 
usb_mark_last_busy(), and runtime suspend arms WAKE_PHY | WAKE_MAGIC | 
WAKE_UCAST instead of WAKE_ANY. With it, the adapter is suspended for 
27.5 s of a 30 s interval:

     2-1.1.3: suspended susp=130671 act=534403
     2-1.1.3: suspended susp=158210 act=536981

and, with runtime PM also enabled for the other devices in the hub, the 
xHCI controller reaches D3 and the package PC10:

     Pkg%pc2 Pkg%pc3 Pkg%pc8 Pkg%pc9 Pk%pc10 SYS%LPI PkgWatt
       13.40    7.53   15.40    1.39   59.08   56.32    0.84

A ping from another subnet still wakes the device. In three attempts, 
the first echo request was answered once, after 78 ms, and lost twice.

The experiment has an obvious cost: broadcast and multicast frames are 
lost while the device is suspended. That includes ARP requests and IPv6 
neighbour solicitations for the station’s own addresses, so a peer 
without a neighbour entry cannot reach the station until it transmits or 
receives a unicast frame.

My questions:

1.  Do the RTL8153 and its successors support ARP and neighbour 
solicitation offload, or wake patterns, while selectively suspended? 
With that, the driver could program the addresses of the interface 
before suspending and keep answering for them, similar to what Wi-Fi 
drivers do with the ARP address list from mac80211. No new switch and no 
loss of reachability would be needed. If the hardware can do it, could 
Realtek add it or share the register description?

2.  If the hardware cannot do it, would you accept a per-device switch 
for the behaviour of the experiment, off by default? A module parameter 
is surely the wrong interface. A private flag (ethtool --set-priv-flags) 
would need no new uAPI, and userspace that knows the network 
configuration (systemd-udevd .link files, NetworkManager) could set it. 
Or do you see a generic interface for a "runtime wake filter", as other 
drivers that runtime suspend with the link up would have the same problem?

3.  Is losing the first frame that wakes the device expected, or should 
it be delivered after the resume?

4.  Is power/control=on by default intended for these adapters? I did 
not find 0bda:8153 in the autosuspend lists of systemd’s hwdb [1] either.


Kind regards,

Paul


[1]: https://github.com/systemd/systemd/tree/main/hwdb.d

[-- Attachment #2: r8152-runtime-suspend-broadcast.diff --]
[-- Type: text/x-patch, Size: 2307 bytes --]

---
 drivers/net/usb/r8152.c | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index d3bb7ee9c9bf3..39c586dc7d0cf 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -802,6 +802,17 @@ enum rtl8152_flags {
 #define DEVICE_ID_THINKPAD_USB_C_DOCK_GEN3		0x3062
 #define DEVICE_ID_THINKPAD_HYBRID_USB_C_DOCK		0xa359
 
+/* While runtime suspended, wake only for link changes, magic packets and
+ * frames addressed to this station. Broadcast and multicast frames then
+ * neither wake the device nor postpone autosuspend, so they are lost while
+ * the device is suspended, including ARP requests and IPv6 neighbour
+ * solicitations for the addresses of this station.
+ */
+static bool runtime_wake_unicast_only;
+module_param(runtime_wake_unicast_only, bool, 0644);
+MODULE_PARM_DESC(runtime_wake_unicast_only,
+		 "Ignore broadcast and multicast frames for runtime PM (default: N)");
+
 struct tally_counter {
 	__le64	tx_packets;
 	__le64	rx_packets;
@@ -2192,7 +2203,8 @@ static void read_bulk_callback(struct urb *urb)
 	if (!netif_carrier_ok(netdev))
 		return;
 
-	usb_mark_last_busy(tp->udev);
+	if (!runtime_wake_unicast_only)
+		usb_mark_last_busy(tp->udev);
 
 	switch (status) {
 	case 0:
@@ -3068,6 +3080,10 @@ static int rx_bottom(struct r8152 *tp, int budget)
 			skb->ip_summed = tp->desc_ops.rx_csum(tp, rx_desc);
 			tp->rx_desc.vlan_tag(rx_desc, skb);
 
+			if (runtime_wake_unicast_only &&
+			    !is_multicast_ether_addr(rx_data))
+				usb_mark_last_busy(tp->udev);
+
 			if (use_frags) {
 				if (rx_frag_head_sz) {
 					memcpy(skb->data, rx_data,
@@ -3841,6 +3857,7 @@ static int rtl8152_set_features(struct net_device *dev,
 }
 
 #define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
+#define WAKE_RUNTIME_UNICAST (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST)
 
 static u32 __rtl_get_wol(struct r8152 *tp)
 {
@@ -4346,7 +4363,8 @@ static bool rtl_can_wakeup(struct r8152 *tp)
 static void rtl_runtime_suspend_enable(struct r8152 *tp, bool enable)
 {
 	if (enable) {
-		__rtl_set_wol(tp, WAKE_ANY);
+		__rtl_set_wol(tp, runtime_wake_unicast_only ?
+			      WAKE_RUNTIME_UNICAST : WAKE_ANY);
 
 		ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
 

^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-11-12  0:53 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-11  0:52 r8152: RTL8153 never runtime suspends with link up on a network with broadcast traffic Paul Menzel
2026-11-12  0:53 ` sashiko-bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox