From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtpbgeu2.qq.com (smtpbgeu2.qq.com [18.194.254.142]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 657723BFE34 for ; Wed, 29 Jul 2026 07:12:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=18.194.254.142 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785309157; cv=none; b=FpEBISpH3RI7oOmFL62TIoAj3Czmr8TvHRA5P2dQUBoFhN42yG2tTg8HezAb4ej8CBpzXKRtrMZ/3Z5wmaJT/8ewemXiIEhgFRuwAVVNp3iC64UoczmIhiuMlS8Kw+5ppGyNZVzJ8dFPaZd1ww6qxxf1UdqWXYA7OPnFGmApm9c= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785309157; c=relaxed/simple; bh=UHRgH4FtYqNF7EtCqqMuW2wWxCLVku61KQCKe+I7unM=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=JsFUKM+0CxmKYwyqU7qtkmdAJUgzqB3jjGPVksklbP104872fXvMRrTOquLG7v1JnrrDorPhN5g4CYwhVSpftB5ebV2YyNnh1JkHu+Ky790VMarvFqh+tOnXmnz3tbJKBlzU/UPC5748aaIE6DfQo0WeogZgtfQ0hxeNyA7ywtQ= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=uniontech.com; spf=pass smtp.mailfrom=uniontech.com; dkim=pass (1024-bit key) header.d=uniontech.com header.i=@uniontech.com header.b=JddSESGS; arc=none smtp.client-ip=18.194.254.142 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=uniontech.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=uniontech.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=uniontech.com header.i=@uniontech.com header.b="JddSESGS" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=uniontech.com; s=onoh2408; t=1785309122; bh=JYabXUw23MXm3K9z3j9Td70Xr3wGG5JkEjW+QaScG3c=; h=From:To:Subject:Date:Message-Id:MIME-Version; b=JddSESGSKCStH6bDJmSrXb+8+p4GSXdK0T9rT5LNYhY3eyXKLwxKYeYhemoV8My0E vjus7vC66mSw6PaZmkb/D2RtLNNwSySDJyIegOFq1vmXXEG0HtN1cawQwuWbTKS8gG kbkctGRr7h3fBr0Qi+y9tGq5Y0l3tsH6ohuQbqQI= X-QQ-mid: zesmtpgz6t1785309107tfa5a5d0b X-QQ-Originating-IP: 7t9aBK2SliuLvTIekGODs2QmU1DxYfC2Y70y8WKn1PY= Received: from localhost.localdomain ( [113.57.152.160]) by bizesmtp.qq.com (ESMTP) with id ; Wed, 29 Jul 2026 15:11:45 +0800 (CST) X-QQ-SSF: 0000000000000000000000000000000 X-QQ-GoodBg: 1 X-BIZMAIL-ID: 3390613808785607158 EX-QQ-RecipientCnt: 15 From: Haowen Tu To: laurent.pinchart@ideasonboard.com, rafael@kernel.org Cc: gregkh@linuxfoundation.org, hansg@kernel.org, kernel@uniontech.com, lenb@kernel.org, linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, mchehab@kernel.org, oneukum@suse.com, pavel@kernel.org, stern@rowland.harvard.edu, tuhaowen@uniontech.com Subject: [PATCH v4 4/4] media: uvcvideo: defer streaming restart after hibernation snapshot Date: Wed, 29 Jul 2026 15:11:23 +0800 Message-Id: <6179cdb467414a1949fabbd4d8dec29affe9c3ea.1785226280.git.tuhaowen@uniontech.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: References: <20260723084633.GE648629@killaraus.ideasonboard.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-QQ-SENDSIZE: 520 Feedback-ID: zesmtpgz:uniontech.com:qybglogicsvrsz:qybglogicsvrsz3b-0 X-QQ-XMAILINFO: MWxZUaxBV+u3CkV4xiJsPpuzP+B01F6nYOpmEQNE4mc27IoqNnCFfpZM DUdDpwShf06PHE25V7raKKMxh8Ki8yAdV+z+sXT6TUdIU1N/3meF1U64c8RCihKawVabCRq R3OUNsJRPP+BPwuiel75vb756ALJgnbMXXoC/4lK1Deuopjz5gnIVwM4RBj9EkDiHd1bbyi Lc95C2yO2yN3Als1hkVjJ+qqZ3HCADquHKsNFZ/7NT8Fq+1zvAm7udP8abqEXPGHnK/Hb6U rRBjOIp0nPI7a8WjgdOJwKA0nJowylbX9am+nKJ1MHd9nZpR7Q9u0jHz+7oWiCmdPtRq2Fq StZs6YUaWSHY0TiDlU4z5Qy0glnqk6r9G09fvKYbIU4Kz2ruYKf7a9WCnNVvK1F0rXLaYi6 M0TMPZ8cy6EN5O9GJgeuK2Yuwi56UUZvGbdhv6ISMz3fh1+4qzvQkzsViOkaEBlZajGwFlu mc5NOckzLR22K5CbpHmwNlHH0SwpXZirpzuoJMzna7R3eOTfJ50SgkmU7Ye1FlASQEZgl3x ny5RGmmSkf2BISWExxoOLkhBNpCFpGpdvN8CywOaa4Nb+ZMEuYRm6Kz7sRXAl61Hp4dAGMX OcSQzCXMteftn1vul89mC5u+xgsKStHiBaq68YDmEblbzujCDGwNeCQjN4eqAREQeAkB4Bi laIXPaSd1MAqZrQyDSxDCf+UM52NeVlPsL7Ee8pGlSzC0nQsriDIvceS7EgYGDMq6lX2L0R a9awfICLICEzkYdcoqKZ8vtiFvO3lLYT2BtxRTghzJZk4xM4deDbj7VvWO6R4HWg9Sp3tlM 4mKnwsnemi9IeVlZA+7P4aqCevc5OuJGNYKsae83cdkZd6n/llKMu7pJfZ8CUFT0ioqoV2W wWUqx+1lUGGQBTG+VqR3qQhgC8zz3R+DK0qiwwAvnJ1hVtn+O6Bd6B6e52PhLwA/bkYveKz bZLHPIwMO/doqZlh116oQ1vtwdGNutOu2ND4utK/gQxVt3KZIGMsLuyH9V/MThwIIEAJ+Rv 8CyVQmOdQsql4bDDmRAMReOCx77duujudPkLZn+OfQLKTibCS3W4WRy750XWk= X-QQ-XMRINFO: Nq+8W0+stu50tPAe92KXseR0ZZmBTk3gLg== X-QQ-RECHKSPAM: 0 When a UVC camera is streaming and the system enters hibernation, the streaming interface is frozen before the snapshot is created. The original kernel then resumes devices with PMSG_THAW so it can write the hibernation image. Restarting UVC streaming during this transient phase can turn the camera LED back on and generate USB traffic even though the normal successful path writes the image and powers off. USB interface resume callbacks do not receive the PM message, so use pm_hibernation_snapshot_done() to detect this phase and defer the streaming restart. The deferred state is kept in the UVC stream. If image writeout succeeds, the system powers off and no restart is needed. If image writeout fails, the PM core sends PM_HIBERNATION_IMAGE_WRITE_FAILED before userspace is thawed; the UVC PM notifier then restarts streams whose resume was deferred. If that recovery restart fails, fall back to the existing streamoff error path so userspace is notified instead of waiting on buffers indefinitely. Signed-off-by: Haowen Tu --- drivers/media/usb/uvc/uvc_driver.c | 56 +++++++++++++++++++++++++++++- drivers/media/usb/uvc/uvc_video.c | 19 +++++++++- drivers/media/usb/uvc/uvcvideo.h | 2 ++ 3 files changed, 75 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 31b4ac3b48c1..3cf861e0fa95 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,8 @@ unsigned int uvc_dbg_param; unsigned int uvc_timeout_param = UVC_CTRL_STREAMING_TIMEOUT; static struct usb_driver uvc_driver; +static LIST_HEAD(uvc_pm_devices); +static DEFINE_MUTEX(uvc_pm_mutex); /* ------------------------------------------------------------------------ * Utility functions @@ -2200,6 +2203,7 @@ static int uvc_probe(struct usb_interface *intf, INIT_LIST_HEAD(&dev->entities); INIT_LIST_HEAD(&dev->chains); INIT_LIST_HEAD(&dev->streams); + INIT_LIST_HEAD(&dev->pm_list); kref_init(&dev->ref); atomic_set(&dev->nmappings, 0); @@ -2346,6 +2350,10 @@ static int uvc_probe(struct usb_interface *intf, if (!(dev->quirks & UVC_QUIRK_DISABLE_AUTOSUSPEND)) usb_enable_autosuspend(udev); + mutex_lock(&uvc_pm_mutex); + list_add_tail(&dev->pm_list, &uvc_pm_devices); + mutex_unlock(&uvc_pm_mutex); + uvc_dbg(dev, PROBE, "UVC device initialized\n"); return 0; @@ -2370,6 +2378,10 @@ static void uvc_disconnect(struct usb_interface *intf) UVC_SC_VIDEOSTREAMING) return; + mutex_lock(&uvc_pm_mutex); + list_del_init(&dev->pm_list); + mutex_unlock(&uvc_pm_mutex); + uvc_unregister_video(dev); kref_put(&dev->ref, uvc_delete); } @@ -2447,6 +2459,41 @@ static int uvc_reset_resume(struct usb_interface *intf) return __uvc_resume(intf, 1); } +static int uvc_pm_notify(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct uvc_device *dev; + struct uvc_streaming *stream; + int ret; + + if (action != PM_HIBERNATION_IMAGE_WRITE_FAILED) + return NOTIFY_DONE; + + mutex_lock(&uvc_pm_mutex); + list_for_each_entry(dev, &uvc_pm_devices, pm_list) { + list_for_each_entry(stream, &dev->streams, list) { + if (!stream->hibernate_resume_deferred) + continue; + + stream->hibernate_resume_deferred = 0; + ret = uvc_video_resume(stream, 0); + if (ret < 0) { + mutex_lock(&stream->queue.mutex); + vb2_streamoff(&stream->queue.queue, + stream->queue.queue.type); + mutex_unlock(&stream->queue.mutex); + } + } + } + mutex_unlock(&uvc_pm_mutex); + + return NOTIFY_OK; +} + +static struct notifier_block uvc_pm_nb = { + .notifier_call = uvc_pm_notify, +}; + /* ------------------------------------------------------------------------ * Module parameters */ @@ -3291,8 +3338,15 @@ static int __init uvc_init(void) uvc_debugfs_init(); + ret = register_pm_notifier(&uvc_pm_nb); + if (ret < 0) { + uvc_debugfs_cleanup(); + return ret; + } + ret = usb_register(&uvc_driver); if (ret < 0) { + unregister_pm_notifier(&uvc_pm_nb); uvc_debugfs_cleanup(); return ret; } @@ -3303,6 +3357,7 @@ static int __init uvc_init(void) static void __exit uvc_cleanup(void) { usb_deregister(&uvc_driver); + unregister_pm_notifier(&uvc_pm_nb); uvc_debugfs_cleanup(); } @@ -3313,4 +3368,3 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); MODULE_VERSION(DRIVER_VERSION); - diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index f6c8e3223796..2c57b7042856 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -2151,11 +2152,27 @@ int uvc_video_resume(struct uvc_streaming *stream, int reset) if (!uvc_queue_streaming(&stream->queue)) return 0; + /* + * Defer restarting the streaming hardware during the transient THAW + * phase after a hibernation snapshot has been created. If writing the + * image succeeds, the system powers off and the restart is not needed. + * If writing fails, the PM core notifies the driver before userspace is + * thawed so deferred streams can be restarted. + */ + if (pm_hibernation_snapshot_done()) { + stream->hibernate_resume_deferred = 1; + return 0; + } + ret = uvc_commit_video(stream, &stream->ctrl); if (ret < 0) return ret; - return uvc_video_start_transfer(stream, GFP_NOIO); + ret = uvc_video_start_transfer(stream, GFP_NOIO); + if (!ret) + stream->hibernate_resume_deferred = 0; + + return ret; } /* ------------------------------------------------------------------------ diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 0a0c01b2420f..c87eaaaf2749 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -475,6 +475,7 @@ struct uvc_streaming { /* Buffers queue. */ unsigned int frozen : 1; + unsigned int hibernate_resume_deferred : 1; struct uvc_video_queue queue; struct workqueue_struct *async_wq; void (*decode)(struct uvc_urb *uvc_urb, struct uvc_buffer *buf, @@ -604,6 +605,7 @@ struct uvc_device { /* Video Streaming interfaces */ struct list_head streams; + struct list_head pm_list; struct kref ref; /* Status Interrupt Endpoint */ -- 2.20.1