* [PATCH RFC net-next] net: qrtr: Wake the system for userspace packets
@ 2026-10-27 0:35 Filippo Falezza
0 siblings, 0 replies; only message in thread
From: Filippo Falezza @ 2026-10-27 0:35 UTC (permalink / raw)
To: Manivannan Sadhasivam, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman
Cc: linux-arm-msm, netdev, linux-kernel, Filippo Falezza
On Qualcomm phones the modem reports an incoming call or SMS as a QMI
indication over QRTR, which ModemManager or a similar daemon reads from
a QRTR socket. While the system is in suspend-to-idle, the GLINK
interrupt that carries the packet still fires, since it is requested
with IRQF_NO_SUSPEND, and the packet is queued on the socket. Nothing
reports a wakeup event though, so the system goes back to idle with
userspace frozen and the call rings out unnoticed.
The transport cannot decide this on its own. Reporting a wakeup for
every GLINK interrupt aborts most suspends, because the name service
and in-kernel QMI clients such as ath10k's WLFW keep talking to the
remotes while devices suspend. Reporting only once the edge is
suspended (in its noirq phase) misses the packets that arrive after
userspace is frozen but before that point: on SM7250 a call and an SMS
that arrived in that window went unnoticed until the next wakeup.
QRTR knows who a packet is for. Let an endpoint name a device to report
wakeup events on, and report a hard wakeup event with
pm_wakeup_dev_event() when a data packet from that endpoint is queued
on a socket owned by userspace. Control packets and packets for kernel
sockets do not wake the system: the kernel handles those while
suspending anyway. Decide before queueing the skb, since the socket
owns it afterwards.
In the SMD/GLINK transport, use the rpmsg device of the IPCRTR channel.
It is wakeup capable but disabled by default, and userspace enables it
through power/wakeup for the remotes it wants to be woken by, typically
the modem.
Signed-off-by: Filippo Falezza <effeffe99@gmail.com>
---
Hello there,
this RFC lets a QRTR remote, in practice the modem, wake the system
when it sends something to a userspace client, so that a suspended
phone notices an incoming call or SMS. I'm sending it as an RFC because
it puts a wakeup policy into the QRTR core, and I'd like to know whether
this is the right layer before going further. I know net-next is closed
for the merge window; this is for discussion only.
I ran into this while bringing up mainline on a Motorola Moto G 5G Plus
(SM7250). With s2idle working, the phone slept through every call: the
GLINK interrupt fired, ModemManager's socket got the indication, and the
system went straight back to idle. My first attempt reported the wakeup
from the GLINK SMEM interrupt once the edge was in its noirq suspend
phase, since reporting every interrupt aborted almost every suspend
(the kernel's own QMI clients talk to the modem while devices suspend).
Logging the suspend phases showed the hole in that: a call and an SMS
that arrived after userspace was frozen but before the noirq phase were
delivered to ModemManager's sockets and never reported, and the phone
only noticed them at the next wakeup. QRTR is the first place that can
tell a frozen userspace client from a kernel socket, hence this patch.
For comparison, the downstream kernel this phone shipped with registers
a wakeup source for the QRTR nodes 0, 3 and 7, hard-coded, and reports
a hard wakeup event for every packet from them, control packets and
kernel-socket traffic included. Here the remote is chosen from
userspace through power/wakeup, and only data for userspace sockets
counts.
Keeping it opt-in matters for another reason. Any user who can open a
QRTR socket can ask the modem for frequent indications, so with wakeup
enabled such a user can wake the system from s2idle again and again
and drain the battery. A single event doesn't keep the system awake,
but it does end each s2idle. That is why wakeup is off by default and
only root can enable it, per remote.
I tested it on the phone on top of next-20261021, with a udev rule that
sets power/wakeup to "enabled" on the modem's IPCRTR rpmsg device. Five
idle suspends in a row completed without an abort. An SMS woke the
phone after 90 minutes and again after 9 minutes in s2idle, an incoming
call woke it and rang, and with pm_test=devices an SMS cut the 60
second wait short. The modem's EFS requests to rmtfs wake the system
as well, which is expected (rmtfs is a userspace client) and matches
downstream. While the system is awake, ModemManager's traffic counts as
wakeup events too; it is harmless, but it keeps the wakeup source's
event count moving.
Three things I'm unsure about and would value opinions on:
The rpmsg device of the IPCRTR channel as the place for the
power/wakeup knob. It is per remote, which is what userspace wants, but
it's a transport detail; a per-node setting in QRTR itself would be the
alternative.
Whether to report only while a system suspend is in progress, rather
than for every userspace packet.
The MHI transport (PCIe modems in laptops) could set wakeup_dev the
same way. I left it out because I have no hardware to test it on.
This exact change was tested on the phone on top of next-20261021: an
SMS woke it after 7 minutes in s2idle, a call after nearly 3 minutes,
and three idle suspends of up to 21 minutes ended only on the power
key. The patch applies to net-next (734bef548a96) and builds there
with W=1 for arm64.
I wrote this patch, ran the tests and drafted this note with the help
of an AI coding assistant (Claude Code). I have reviewed the patch
myself, and the results above are from the phone.
Thanks,
Filippo
---
net/qrtr/af_qrtr.c | 18 ++++++++++++++++++
net/qrtr/qrtr.h | 4 ++++
net/qrtr/smd.c | 14 +++++++++++++-
3 files changed, 35 insertions(+), 1 deletion(-)
diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c
index e7b3647424b8..5481652cb0ca 100644
--- a/net/qrtr/af_qrtr.c
+++ b/net/qrtr/af_qrtr.c
@@ -5,6 +5,7 @@
*/
#include <linux/module.h>
#include <linux/netlink.h>
+#include <linux/pm_wakeup.h>
#include <linux/qrtr.h>
#include <linux/termios.h> /* For TIOCINQ/OUTQ */
#include <linux/spinlock.h>
@@ -460,6 +461,7 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len)
size_t size;
unsigned int ver;
size_t hdrlen;
+ bool wake;
if (len == 0 || len & 3)
return -EINVAL;
@@ -548,11 +550,27 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len)
if (!ipc)
goto err;
+ /*
+ * If userspace is frozen for a system suspend, nothing reads
+ * this packet until something else wakes the system: an
+ * incoming call or message would go unnoticed. Let the
+ * endpoint wake the system, if wakeup is enabled for it.
+ * Kernel sockets (the name service, in-kernel QMI clients) are
+ * served while suspending, and their traffic must not abort
+ * the suspend. Decide before queueing: once queued, the skb
+ * belongs to the socket and may already be freed.
+ */
+ wake = ep->wakeup_dev && cb->type == QRTR_TYPE_DATA &&
+ !ipc->sk.sk_kern_sock;
+
if (sock_queue_rcv_skb(&ipc->sk, skb)) {
qrtr_port_put(ipc);
goto err;
}
+ if (wake)
+ pm_wakeup_dev_event(ep->wakeup_dev, 0, true);
+
qrtr_port_put(ipc);
}
diff --git a/net/qrtr/qrtr.h b/net/qrtr/qrtr.h
index de2de69a6199..089302323310 100644
--- a/net/qrtr/qrtr.h
+++ b/net/qrtr/qrtr.h
@@ -4,6 +4,7 @@
#include <linux/types.h>
+struct device;
struct sk_buff;
/* endpoint node id auto assignment */
@@ -12,6 +13,8 @@ struct sk_buff;
/**
* struct qrtr_endpoint - endpoint handle
* @xmit: Callback for outgoing packets
+ * @wakeup_dev: Device to report a wakeup event on when a data packet from
+ * this endpoint is queued for a userspace socket, or NULL
*
* The socket buffer passed to the xmit function becomes owned by the endpoint
* driver. As such, when the driver is done with the buffer, it should
@@ -19,6 +22,7 @@ struct sk_buff;
*/
struct qrtr_endpoint {
int (*xmit)(struct qrtr_endpoint *ep, struct sk_buff *skb);
+ struct device *wakeup_dev;
/* private: not for endpoint use */
struct qrtr_node *node;
};
diff --git a/net/qrtr/smd.c b/net/qrtr/smd.c
index c91bf030fbc7..e3b2b67dfcce 100644
--- a/net/qrtr/smd.c
+++ b/net/qrtr/smd.c
@@ -4,6 +4,7 @@
* Copyright (c) 2013, The Linux Foundation. All rights reserved.
*/
+#include <linux/device.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/rpmsg.h>
@@ -68,10 +69,20 @@ static int qcom_smd_qrtr_probe(struct rpmsg_device *rpdev)
qdev->channel = rpdev->ept;
qdev->dev = &rpdev->dev;
qdev->ep.xmit = qcom_smd_qrtr_send;
+ qdev->ep.wakeup_dev = &rpdev->dev;
+
+ /*
+ * Packets from the remote, such as an incoming call or SMS from the
+ * modem, may wake the system. Keep it disabled by default, so that
+ * userspace enables it only for the remotes it wants to be woken by.
+ */
+ device_set_wakeup_capable(&rpdev->dev, true);
rc = qrtr_endpoint_register(&qdev->ep, QRTR_EP_NID_AUTO);
- if (rc)
+ if (rc) {
+ device_init_wakeup(&rpdev->dev, false);
return rc;
+ }
dev_set_drvdata(&rpdev->dev, qdev);
@@ -85,6 +96,7 @@ static void qcom_smd_qrtr_remove(struct rpmsg_device *rpdev)
struct qrtr_smd_dev *qdev = dev_get_drvdata(&rpdev->dev);
qrtr_endpoint_unregister(&qdev->ep);
+ device_init_wakeup(&rpdev->dev, false);
dev_set_drvdata(&rpdev->dev, NULL);
}
---
base-commit: 734bef548a96e8774d6eef5dfa2026c6edc4e80b
change-id: 20261027-qrtr-wakeup-70dcf7dc853f
Best regards,
--
Filippo Falezza <effeffe99@gmail.com>
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-10-27 0:35 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-27 0:35 [PATCH RFC net-next] net: qrtr: Wake the system for userspace packets Filippo Falezza
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox