From nobody Wed Jun 17 03:56:43 2026 Received: from mail-pj1-f49.google.com (mail-pj1-f49.google.com [209.85.216.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 78E6E3E9F96 for ; Wed, 22 Apr 2026 13:11:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776863463; cv=none; b=gQUoyVR31DUvQCHxRfBaJmwycgV3Lgh4XI0rqDlYYmCabo32jSVdk6QUu2wEB4CMEW49t2bYCSSi+JyH4NGS1gkcUEtquunMUv8PDxXWW0QZtXUTj3CD9TyoyWHbnhdu4y85o85zyXiloHwo6+gW/2fWqbj4aV5eRaAialRKXYE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776863463; c=relaxed/simple; bh=ElyyymLN3BzEU2n3paseyXgS1oFdDA7FSr0KdZ24I/8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=fJiLeaLHrarPcP7kza8d+JgMh4Jyxl1WR693LqK+a5CUkOy7czr2bVeqpRFSXYJZ5NSHiWAR+LP9a3SgU+YtsIfJvYOllTP3apvw1QnJqqfCM7vnWtn90K9ov6596Ko3geuJCuMUMJ/67zbUtBStk0GeLz4MdH+L1BGrZLnU+4c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=mBMolH2C; arc=none smtp.client-ip=209.85.216.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="mBMolH2C" Received: by mail-pj1-f49.google.com with SMTP id 98e67ed59e1d1-35691a231a7so3695257a91.3 for ; Wed, 22 Apr 2026 06:11:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1776863461; x=1777468261; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=lmg393/U6YNbXTTx1LhzYWJYt4NvUfYyO+r0SFXM9Jg=; b=mBMolH2CAvdqXCLhzBxm0yZkgERl/qTHm4eChkOWqM1wwesmM3/YCgJ/teFK31fzHw nxMobuXXBNw4M3Coz80d6WK04NAmfjcMOyVJ0gLSPsNjP2TU2xem7afQf7SpcgZf/eB2 hFHK0UKLpJYr3IQb8VN/ewukAWMhBvgS8H2WMOEKkHMtuY1d+ky/j3jmEYo7Cox+EbXH HpHihg8wn0puYBHJS0jlsrUFnyEDCbaihbMQ0OgSBH2QzM5kIeXirh0N1JN8rd6LlCjY cGDMJppyAlNPeW0fMSM6Yk4JHB0vGHtguzQRFzPXNpP3Zk1AG/8A8BS3IxfN9+7sre2k YXlQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1776863461; x=1777468261; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=lmg393/U6YNbXTTx1LhzYWJYt4NvUfYyO+r0SFXM9Jg=; b=NPGmqVK7bflcYpmdgEldFod0eOL3dUC71tCR/FxQQ/5I21LAdU5/3OmqIQaRhdkvKB qxdQZtLVx4V9lfZ86c3grsDbKf5s+JkljMBV4axitFdMqVZ0wZQyq1u+1KzlolfWTQam GNpGb67X8q+RDjy+EZ+WVGFoZpO4yJCHtC+Xu/j95s8W3Epnlez9YlWIFnfOn+1H3jtR j2EaK1EQzCO88T/uPKqedsbkwsGtveSA8AgIN3++aB809bxKNuz6c+mtSe3XXlhIYHTE eCUA5MmfoEafgtT3zrwCXL18ov8zIp/nWOh2QR41YNVwNukG7WYsoYMkUboL1/qdZcrS ZIXg== X-Forwarded-Encrypted: i=1; AFNElJ/O8X+EWFALOXIDle9+6amJTRy9bUDXoCkLE6bCviw8g/dgwJf+unm3VibsAF4XmGAXiPBteDPfXl5o7cY=@vger.kernel.org X-Gm-Message-State: AOJu0YxG061p0zabuEUZDIw+ThhVbh1a0A4id1tcPyQs1ebJlKvUrrXW vjk6sUn/N3BlOSWsMH3EHGiQnt4xRyxuTEsn91lgtMJMxHJc+7ZAXGwP X-Gm-Gg: AeBDieu1RtBF4qBR3c2o5LEfyzQD38UpoBi4so2bmwKh6hAL/HoGaWWiXw45X0dh/n0 XjB3ZnBcmgTGfeudYda+/9iMQZCF4+HMHVQRY397mYsokFuhglTZt1tx1vzKE1pQtWfxC5xulqA d+Q5GpQGqW58KeSziwe90FG7spc3puWsXlptegT3Aw3iR/B/22M/ehsxChKK6ilJcFE+NI++OGo N0RLsLgIpEkU8gVCIOPLYOio/5cnYURBLmKDefvXI1nygS8FD8RTeWo8MhT7HfjSGD+fqMcU4nx HNIPuGwBN+rDQl5IBMRF2UyXLV3vBC4/AtDRvhD6h/naYquETLS1AFFgmsHu5MRY+iCNUlM+7c1 LC7cTDGqmf/0C+8mFKfkbBw5xKVhYPj0AVmNjnn2PrvVuuIoa6WGOQUo4b6+kIcxFKamdfBsB79 SUinecRxvEniRHZNHF0Mlre4pFe0JucpIsJ620b5y4RMSNIHI5RJjGnM26c84LEEvc/omTZhNUD Ra3UTBb9SFtAULB4zVc3o6tbDCYRbxCT4tW4w== X-Received: by 2002:a17:903:3204:b0:2b7:895f:407b with SMTP id d9443c01a7336-2b7895f4214mr64124515ad.21.1776863460366; Wed, 22 Apr 2026 06:11:00 -0700 (PDT) Received: from baver-zenith.localdomain ([124.49.88.131]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2b606ce9891sm127892235ad.83.2026.04.22.06.10.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 22 Apr 2026 06:11:00 -0700 (PDT) From: Sungho Bae To: mst@redhat.com, jasowang@redhat.com Cc: xuanzhuo@linux.alibaba.com, eperezma@redhat.com, virtualization@lists.linux.dev, linux-kernel@vger.kernel.org, Sungho Bae Subject: [RFC PATCH v3 1/4] virtio: separate PM restore and reset_done paths Date: Wed, 22 Apr 2026 22:10:11 +0900 Message-Id: <20260422131014.956-2-baver.bae@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260422131014.956-1-baver.bae@gmail.com> References: <20260422131014.956-1-baver.bae@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Sungho Bae Refactor virtio_device_restore_priv() by extracting the common device re-initialization sequence into virtio_device_reinit(). This helper performs the full bring-up sequence: reset, status acknowledgment, feature finalization, and feature negotiation. virtio_device_restore() and virtio_device_reset_done() now each call virtio_device_reinit() directly instead of going through a boolean- dispatched wrapper. This makes each path independently readable and extensible without further complicating the dispatch logic. A follow-up series will add noirq PM callbacks that only affect the restore path; having the two paths separated avoids adding more conditionals to a shared function. No functional change. Signed-off-by: Sungho Bae --- drivers/virtio/virtio.c | 81 +++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 31 deletions(-) diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index 5bdc6b82b30b..98f1875f8df1 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c @@ -588,7 +588,7 @@ void unregister_virtio_device(struct virtio_device *dev) } EXPORT_SYMBOL_GPL(unregister_virtio_device); =20 -static int virtio_device_restore_priv(struct virtio_device *dev, bool rest= ore) +static int virtio_device_reinit(struct virtio_device *dev) { struct virtio_driver *drv =3D drv_to_virtio(dev->dev.driver); int ret; @@ -613,35 +613,9 @@ static int virtio_device_restore_priv(struct virtio_de= vice *dev, bool restore) =20 ret =3D dev->config->finalize_features(dev); if (ret) - goto err; - - ret =3D virtio_features_ok(dev); - if (ret) - goto err; - - if (restore) { - if (drv->restore) { - ret =3D drv->restore(dev); - if (ret) - goto err; - } - } else { - ret =3D drv->reset_done(dev); - if (ret) - goto err; - } - - /* If restore didn't do it, mark device DRIVER_OK ourselves. */ - if (!(dev->config->get_status(dev) & VIRTIO_CONFIG_S_DRIVER_OK)) - virtio_device_ready(dev); - - virtio_config_core_enable(dev); - - return 0; + return ret; =20 -err: - virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED); - return ret; + return virtio_features_ok(dev); } =20 #ifdef CONFIG_PM_SLEEP @@ -668,7 +642,33 @@ EXPORT_SYMBOL_GPL(virtio_device_freeze); =20 int virtio_device_restore(struct virtio_device *dev) { - return virtio_device_restore_priv(dev, true); + struct virtio_driver *drv =3D drv_to_virtio(dev->dev.driver); + int ret; + + ret =3D virtio_device_reinit(dev); + if (ret) + goto err; + + if (!drv) + return 0; + + if (drv->restore) { + ret =3D drv->restore(dev); + if (ret) + goto err; + } + + /* If restore didn't do it, mark device DRIVER_OK ourselves. */ + if (!(dev->config->get_status(dev) & VIRTIO_CONFIG_S_DRIVER_OK)) + virtio_device_ready(dev); + + virtio_config_core_enable(dev); + + return 0; + +err: + virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED); + return ret; } EXPORT_SYMBOL_GPL(virtio_device_restore); #endif @@ -698,11 +698,30 @@ EXPORT_SYMBOL_GPL(virtio_device_reset_prepare); int virtio_device_reset_done(struct virtio_device *dev) { struct virtio_driver *drv =3D drv_to_virtio(dev->dev.driver); + int ret; =20 if (!drv || !drv->reset_done) return -EOPNOTSUPP; =20 - return virtio_device_restore_priv(dev, false); + ret =3D virtio_device_reinit(dev); + if (ret) + goto err; + + ret =3D drv->reset_done(dev); + if (ret) + goto err; + + /* If reset_done didn't do it, mark device DRIVER_OK ourselves. */ + if (!(dev->config->get_status(dev) & VIRTIO_CONFIG_S_DRIVER_OK)) + virtio_device_ready(dev); + + virtio_config_core_enable(dev); + + return 0; + +err: + virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED); + return ret; } EXPORT_SYMBOL_GPL(virtio_device_reset_done); =20 --=20 2.43.0 From nobody Wed Jun 17 03:56:43 2026 Received: from mail-pl1-f173.google.com (mail-pl1-f173.google.com [209.85.214.173]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 453B93D9DA2 for ; Wed, 22 Apr 2026 13:11:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.173 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776863467; cv=none; b=Yw6EJB7Fap1bapxrW4t5dA+mT7ulfirwfAFR53rs0KJwlNMWzxDfK+mF4Ow83FiXdl/LEiUTWwCayZS4/xAYK2f/+GBNfzp7NATlwI/QaSF5bvZdpB4D5WqmLg89ogeesYJpi5rFbzjBSNl+YJ/nUa66c9Uip73RM5BFCVN+B74= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776863467; c=relaxed/simple; bh=6dX0PzOsvQzuVsAQ1OLovx2RSIPr5HJX+ZoCwBnrXJ0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=oxXiMM5GIbsc53fhqqX7Kyq7EY5K7TG0KPtxzVeVaqFTVlkENVwn+6n4orQ32NQj6CklAo6mOktHEjt2Qo2atZ8C4e1WkYYQsChf8ftMwAb9TsIxEo3dO/Vi3o/gE1RfEvDfscYuzjeQiuc9Qp4kNvGPabF9ccxSE/LwBuT73+o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=ILhH4y8J; arc=none smtp.client-ip=209.85.214.173 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ILhH4y8J" Received: by mail-pl1-f173.google.com with SMTP id d9443c01a7336-2ad9a9be502so33660385ad.0 for ; Wed, 22 Apr 2026 06:11:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1776863464; x=1777468264; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=opyqOEmxu5ONdPehlI5jbPlGmvm0e7vGWmLDp5P5SYs=; b=ILhH4y8JmSxUqmvqfERpAQzrjndZ1uUh62PJDsfTZVWZ/o8PtIPjWRVmJ2TA6vehJK eqtmEdmECjxJPRp3jVMAaYiWT/WKTQoKSOZ5Iqg0dbAC8Kf0N6yR15SQe+zh27FMDEAY Lo59Zc7yEarI5US9XA7tczgSKzAj2MhvVYzEYAb8BPDmi9auVCu7vNk605YieKgtFs4e jbMsyM9xfV+eFQKE8gPt2tDEMaTuiTR0ncyDHj28F7OVJlxeN3imxSqIQySLbJtgQr6k u8fvYmJVBisNL4XtmqbF1ggB5ECTRgTaqWRanlM1UlZwhBNLd+s2ptktya8oSt3PWSS9 cQMg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1776863464; x=1777468264; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=opyqOEmxu5ONdPehlI5jbPlGmvm0e7vGWmLDp5P5SYs=; b=LVBFAjwcp//E7XgboEN076GtYXhrRUSCr7ymytt0X/s1BM1BhMc6JOZ2dKdbUtQOL+ xhvfT3uU1a1e4hLA4eQOIQhWAWR7WuL0uP7g6xgs5v4BFAmrHh4o9segIJDgHKzytcw1 XkBLPeWEe/Fb2n/bQYIMe4FgaLmRPINmYgOVmU6MxzSExDy/RIiam0gC1WOS22LHr2nL oABcTHBTwbiOqJSJWyfH3wEosbqieBtSZ1LserTjEh1WE86iisCUIJLtq0QKvMHFGWn3 tw+IJkbK+nFrKuw5DxEnQ5KyqzfH+7qoSYSf+92ThwSksO+jYtJMmbjkJ3vZJIa0HOoc 9obw== X-Forwarded-Encrypted: i=1; AFNElJ8gqipc1XNTgKbq3UiBHL0gpf4njtQ0zY10jn3XZe0PWOvqWY3FUNP1v8ZP0EPZTESWMuqf+ugue6nxBOU=@vger.kernel.org X-Gm-Message-State: AOJu0Ywp0YWjLTavJVuaoUuESiTWU1f+4qgn4QIhm46SJFHv07bS6wcO DhmiPiVZu4gK2aiTkvYbJdq+ugDGpAcU6SuvtASKO83HuxsehAMb/q3JO2Pjvh3w X-Gm-Gg: AeBDievi1WG+m3vA6etgUK8EYw0uQxjqblhFMKbxRhfN7HsuwEuf/U7g1CAMgAYKfDy HzHyqWwNMB/n2wPQyZj3gKc7fEH+ymwx1dZ1QrTgc5U5QGl8t20pCDeSRVpNae1QoCecPVldUZB lyUpwxke+ytVcmajQR4H8RyCh/Ou1sGbHPO0+tM3/WMk8vBcM0Z1i0SwACdkxAuFRvytx77xNno 5AI5IvyPq3Fm5qmfkHVQz7zaOvUXptrVAbPmOwTk1vuhU30HDmfYDlmAvTuzaqEC+0QmCVS5oaI P8w9O16a4Wy/x6CfonwHinchD35iXzHTzLNblwsL3dwWzSX/qo7WkmJLVbZItHDcfdwW4Rhhrr5 vrPsNcIPnOxvCdH7XsklvzjfF8dlfqBtdIgVW+nMNWY+lBZaGls7a4JdewKdVLpNkN2eMf1qu+N jhIbAKVqRfFcrmMS61l5I2S26qouv12YFYb49WoBRqQhgMeZ4pTjwFXhrlVI1EfjnaaNDs2usAv X1IBBWa1pMplSfHLkJIC32AcRBvK0706tKXsa7Nmfmt1acj X-Received: by 2002:a17:903:11d0:b0:2b2:ec00:7966 with SMTP id d9443c01a7336-2b5f9f1ab06mr250725425ad.21.1776863462787; Wed, 22 Apr 2026 06:11:02 -0700 (PDT) Received: from baver-zenith.localdomain ([124.49.88.131]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2b606ce9891sm127892235ad.83.2026.04.22.06.11.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 22 Apr 2026 06:11:02 -0700 (PDT) From: Sungho Bae To: mst@redhat.com, jasowang@redhat.com Cc: xuanzhuo@linux.alibaba.com, eperezma@redhat.com, virtualization@lists.linux.dev, linux-kernel@vger.kernel.org, Sungho Bae Subject: [RFC PATCH v3 2/4] virtio_ring: export virtqueue_reinit_vring() for noirq restore Date: Wed, 22 Apr 2026 22:10:12 +0900 Message-Id: <20260422131014.956-3-baver.bae@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260422131014.956-1-baver.bae@gmail.com> References: <20260422131014.956-1-baver.bae@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Sungho Bae After a device reset in noirq context the existing vrings must be re-initialized without any memory allocation, because GFP_KERNEL is not available. The internal helpers virtqueue_reset_split() and virtqueue_reset_packed() already reset vring indices and descriptor state in place. Add a thin exported wrapper, virtqueue_reinit_vring(), that dispatches to the appropriate helper based on the ring layout. This will be used by a subsequent patch that adds noirq system-sleep PM callbacks for virtio-mmio. Signed-off-by: Sungho Bae --- drivers/virtio/virtio_ring.c | 30 ++++++++++++++++++++++++++++++ include/linux/virtio_ring.h | 3 +++ 2 files changed, 33 insertions(+) diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index fbca7ce1c6bf..528157b1211d 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -3936,5 +3936,35 @@ void virtqueue_map_sync_single_range_for_device(cons= t struct virtqueue *_vq, } EXPORT_SYMBOL_GPL(virtqueue_map_sync_single_range_for_device); =20 +/** + * virtqueue_reinit_vring - reinitialize vring state without reallocation + * @_vq: the virtqueue + * + * Reset the avail/used indices and descriptor state of an existing + * virtqueue so it can be reused after a device reset. No memory is + * allocated or freed, making this safe for use in noirq context. + * + * The caller must ensure that all in-flight buffers have been completed + * or detached before invoking this function. Calling it with outstanding + * descriptors will corrupt the free-list state because num_free is + * unconditionally restored to the ring's maximum capacity while the + * desc_extra next-chain and free_head reflect only the partial free list + * that existed at reset time. + */ +void virtqueue_reinit_vring(struct virtqueue *_vq) +{ + struct vring_virtqueue *vq =3D to_vvq(_vq); + unsigned int num =3D virtqueue_is_packed(vq) ? + vq->packed.vring.num : vq->split.vring.num; + + WARN_ON(vq->vq.num_free !=3D num); + + if (virtqueue_is_packed(vq)) + virtqueue_reset_packed(vq); + else + virtqueue_reset_split(vq); +} +EXPORT_SYMBOL_GPL(virtqueue_reinit_vring); + MODULE_DESCRIPTION("Virtio ring implementation"); MODULE_LICENSE("GPL"); diff --git a/include/linux/virtio_ring.h b/include/linux/virtio_ring.h index c97a12c1cda3..26c7c9d0a151 100644 --- a/include/linux/virtio_ring.h +++ b/include/linux/virtio_ring.h @@ -118,6 +118,9 @@ void vring_del_virtqueue(struct virtqueue *vq); /* Filter out transport-specific feature bits. */ void vring_transport_features(struct virtio_device *vdev); =20 +/* Reinitialize a virtqueue without reallocation (safe in noirq context) */ +void virtqueue_reinit_vring(struct virtqueue *_vq); + irqreturn_t vring_interrupt(int irq, void *_vq); =20 u32 vring_notification_data(struct virtqueue *_vq); --=20 2.43.0 From nobody Wed Jun 17 03:56:43 2026 Received: from mail-pl1-f170.google.com (mail-pl1-f170.google.com [209.85.214.170]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F06BC3C0602 for ; Wed, 22 Apr 2026 13:11:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.170 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776863467; cv=none; b=G2QFIc432t2JkvAaNWVre8CM1sobPwVaW2Gk25PV/Fxzlq2xa98g3u3IfJPcdTuC/s8c/vU9tX/KSUf60Y5f9H0SjFrQKqcD2u0Yrl6UaW72ogtfAdV6VtUr1xVb+sABBHR82CWMchwsDJP/rW2d1Evty4MfaTEAIN2LX9PHPm4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776863467; c=relaxed/simple; bh=03lkltZM33ly/Y1bi8+MQwlUOAdudcrWYo3uPRrj2Pw=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=e/oSCHclRmR1EGITQ6k34MRg5I3ikw2gAuMPOYnFj+o9c70AtVj4Oexmp86eUmppAZL1PHMpQ2rSVbtby221ooIizxkGoxadx1rkE/nEFLN2gbMTTsAXOLxCJWdZrgfFdi5LnaLKRKUY+KWZ82mtfKZUqlOEKaWYiAgQhMWp6j0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=e1ltMMUg; arc=none smtp.client-ip=209.85.214.170 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="e1ltMMUg" Received: by mail-pl1-f170.google.com with SMTP id d9443c01a7336-2ab39b111b9so22154995ad.1 for ; Wed, 22 Apr 2026 06:11:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1776863465; x=1777468265; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=BfTqY76zyVDHAOhHLjOsF+fg1eNIaQE5Yd8/TQ9BvSE=; b=e1ltMMUgdd4koMcD7kyKi1Cehd75/OtSBi9XOYmXQyY4BCS7omMt9CAj+TcGOYtiP2 PHlEC+D9YBCqDDlPoa0tJVAV048SUFG5RFMnXl2+HmyM9DMIEBqTuL2Hl25kSfzz3ifx Efd/R9yXYUrLhWrME6owHfeSU6rzxpD9gdt08qz08hg5O0CHMhT8kd3s2BMYkjoQXT4P tqcx3fyDtoTygW6hKZzEPyP+QDSmRHZeM6E6pIJX0bftdwfFt8nzQsiAom+nv9WS7Fje EwXdb3ktHmJdfsZpgXoAgIkE8TxDZhRSzlBISJF7ngXv5z/p6miXBTei0CWPZHbPiu9e iLfg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1776863465; x=1777468265; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=BfTqY76zyVDHAOhHLjOsF+fg1eNIaQE5Yd8/TQ9BvSE=; b=PWDATKcMcci66WZX4HfS8oL0ZWUu1W6/SQDYIO5Eb9G09VrJL3/7nSZn3IFsdxfIn1 V7amOpXeMIpeKnpJyXEWKlI7C/aGExhpqBIbupc1NktowFnRZ5a+hHcMom6fNHNDnr8e iZ2neSskvzSypYvBqtALNcF7uEb4b87RO5JDsQeRzbWSCD9mHY8zZlD4vQaoYzEwLn5f mwox+q1CN2ACbxR/mTtbIGv7zfDQ+9x9XZtoi5Q7DAfM8db9rVd4ztxuIkBNcDlhhR6q 68+GmLWEMzwnpmS3DhtdC9zQWMoKRF1ILv4GfiDThuY+c4EvXgAEq+3kZcdjjuL/D3fj 7FSw== X-Forwarded-Encrypted: i=1; AFNElJ91r4Gp8dFmFcdG5qE4QW2xXEn6MCjYzHYYY6j1//UIR3sTkx5EB0gIy5fS9PAhRTjIhfcl8GW2RhHpM/8=@vger.kernel.org X-Gm-Message-State: AOJu0YyTYPTd7qWQUKyZtD83evucJXaik7nGCxV40n4EcbY+wlxAkgns DM1lTu+eQ9Ug4XhtYZRTa9AlwAMjHY5Y//8MF8dBWqjqJEpUVcxOLXwB X-Gm-Gg: AeBDieuwX9XSAVaEvovdHR3FHqH52VIXec2FdBSrar4l18LmhcZEUKlIEOkVh1oSifO Lb2u5dG/F4ozW/4+Hb725pRPPaUTCmjGPWUcmfNi02/0fFe/LtQN8UT8ogAB7p21wAQgw3V9gz0 CIUR+dBHG/jXcsSCsHFcJBdj428PnNW7JRryf0syCpmD5OP2dqqrFyqT8PCvT98AkSG32SVdc55 PRbvDwAfv7P4KczysnCyU0bo0n6j2wUZV/49W5xSw+iLvXFkegrSYPRNlbZ/yutpTYQsOURUpsV OSKG1sieQv3UMNojVDU15onH7mNDDJzDESIRuUQkSHn7vl21hMbvBRbx8qkSoySVQJGQ92suoJ5 CGT2adNv1mnzi9u+VdtAtYKE+0jabtSP7/Z0lfUqKknb1UjYbfrBolmXGOWSotTX2usQxqLeC5g iVaq3jk0of2XJAXIccKfotm1uZQsAvgZUrqScA4Fy1eUZLpROAm8clUbQArfjcdLj1rg3X5aNeR M12WHNlIgcO0dWJKVdXdhVxL5ycMJpoVJCahA== X-Received: by 2002:a17:903:246:b0:2b6:309:9f72 with SMTP id d9443c01a7336-2b603099feamr202064555ad.21.1776863465116; Wed, 22 Apr 2026 06:11:05 -0700 (PDT) Received: from baver-zenith.localdomain ([124.49.88.131]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2b606ce9891sm127892235ad.83.2026.04.22.06.11.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 22 Apr 2026 06:11:04 -0700 (PDT) From: Sungho Bae To: mst@redhat.com, jasowang@redhat.com Cc: xuanzhuo@linux.alibaba.com, eperezma@redhat.com, virtualization@lists.linux.dev, linux-kernel@vger.kernel.org, Sungho Bae Subject: [RFC PATCH v3 3/4] virtio: add noirq system sleep PM infrastructure Date: Wed, 22 Apr 2026 22:10:13 +0900 Message-Id: <20260422131014.956-4-baver.bae@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260422131014.956-1-baver.bae@gmail.com> References: <20260422131014.956-1-baver.bae@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Sungho Bae Some virtio-mmio devices, such as virtio-clock or virtio-regulator, must become operational before the regular PM restore callback runs because other devices may depend on them. Add the core infrastructure needed to support noirq system-sleep PM callbacks for virtio transports: - virtio_add_status_noirq(): status helper without might_sleep(). - virtio_features_ok_noirq(): feature negotiation without might_sleep(). - virtio_reset_device_noirq(): device reset that skips virtio_synchronize_cbs() (IRQ handlers are already quiesced in the noirq phase). - virtio_device_reinit_noirq(): full noirq bring-up sequence using the above helpers. - virtio_config_core_enable_noirq(): config enable with irqsave locking. - virtio_device_ready_noirq(): marks DRIVER_OK without virtio_synchronize_cbs(). Add freeze_noirq/restore_noirq callbacks to struct virtio_driver and provide matching helper wrappers in the virtio core: - virtio_device_freeze_noirq(): forwards to drv->freeze_noirq(). - virtio_device_restore_noirq(): runs the noirq bring-up sequence, resets existing vrings via the new config_ops->reset_vqs() hook, then calls drv->restore_noirq(). Modify virtio_device_restore() so that when a driver provides restore_noirq, the normal-phase restore skips the re-initialization that was already done in the noirq phase. Signed-off-by: Sungho Bae --- drivers/virtio/virtio.c | 193 ++++++++++++++++++++++++++++++++-- include/linux/virtio.h | 10 ++ include/linux/virtio_config.h | 29 +++++ 3 files changed, 226 insertions(+), 6 deletions(-) diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index 98f1875f8df1..124ada693f5f 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c @@ -193,6 +193,17 @@ static void virtio_config_core_enable(struct virtio_de= vice *dev) spin_unlock_irq(&dev->config_lock); } =20 +static void virtio_config_core_enable_noirq(struct virtio_device *dev) +{ + unsigned long flags; + + spin_lock_irqsave(&dev->config_lock, flags); + dev->config_core_enabled =3D true; + if (dev->config_change_pending) + __virtio_config_changed(dev); + spin_unlock_irqrestore(&dev->config_lock, flags); +} + void virtio_add_status(struct virtio_device *dev, unsigned int status) { might_sleep(); @@ -200,6 +211,20 @@ void virtio_add_status(struct virtio_device *dev, unsi= gned int status) } EXPORT_SYMBOL_GPL(virtio_add_status); =20 +/* + * Same as virtio_add_status() but without the might_sleep() assertion, + * so it is safe to call from noirq context. + * + * This assumes that the device's get_status and set_status operations are + * also noirq-safe. Therefore, the device must garantee that get_status and + * set_status can be called from noirq context. + */ +void virtio_add_status_noirq(struct virtio_device *dev, unsigned int statu= s) +{ + dev->config->set_status(dev, dev->config->get_status(dev) | status); +} +EXPORT_SYMBOL_GPL(virtio_add_status_noirq); + /* Do some validation, then set FEATURES_OK */ static int virtio_features_ok(struct virtio_device *dev) { @@ -234,6 +259,38 @@ static int virtio_features_ok(struct virtio_device *de= v) return 0; } =20 +/* noirq-safe variant: no might_sleep(), uses virtio_add_status_noirq() */ +static int virtio_features_ok_noirq(struct virtio_device *dev) +{ + unsigned int status; + + if (virtio_check_mem_acc_cb(dev)) { + if (!virtio_has_feature(dev, VIRTIO_F_VERSION_1)) { + dev_warn(&dev->dev, + "device must provide VIRTIO_F_VERSION_1\n"); + return -ENODEV; + } + + if (!virtio_has_feature(dev, VIRTIO_F_ACCESS_PLATFORM)) { + dev_warn(&dev->dev, + "device must provide VIRTIO_F_ACCESS_PLATFORM\n"); + return -ENODEV; + } + } + + if (!virtio_has_feature(dev, VIRTIO_F_VERSION_1)) + return 0; + + virtio_add_status_noirq(dev, VIRTIO_CONFIG_S_FEATURES_OK); + status =3D dev->config->get_status(dev); + if (!(status & VIRTIO_CONFIG_S_FEATURES_OK)) { + dev_err(&dev->dev, "virtio: device refuses features: %x\n", + status); + return -ENODEV; + } + return 0; +} + /** * virtio_reset_device - quiesce device for removal * @dev: the device to reset @@ -267,6 +324,24 @@ void virtio_reset_device(struct virtio_device *dev) } EXPORT_SYMBOL_GPL(virtio_reset_device); =20 +/** + * virtio_reset_device_noirq - noirq-safe variant of virtio_reset_device() + * @dev: the device to reset + */ +void virtio_reset_device_noirq(struct virtio_device *dev) +{ +#ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION + /* + * The noirq stage runs with device IRQ handlers disabled, so + * virtio_synchronize_cbs() must not be called here. + */ + virtio_break_device(dev); +#endif + + dev->config->reset(dev); +} +EXPORT_SYMBOL_GPL(virtio_reset_device_noirq); + static int virtio_dev_probe(struct device *_d) { int err, i; @@ -539,6 +614,7 @@ int register_virtio_device(struct virtio_device *dev) dev->config_driver_disabled =3D false; dev->config_core_enabled =3D false; dev->config_change_pending =3D false; + dev->noirq_restore_done =3D false; =20 INIT_LIST_HEAD(&dev->vqs); spin_lock_init(&dev->vqs_list_lock); @@ -618,6 +694,41 @@ static int virtio_device_reinit(struct virtio_device *= dev) return virtio_features_ok(dev); } =20 +/* noirq-safe variant of virtio_device_reinit() */ +static int virtio_device_reinit_noirq(struct virtio_device *dev) +{ + struct virtio_driver *drv =3D drv_to_virtio(dev->dev.driver); + int ret; + + /* + * We always start by resetting the device, in case a previous + * driver messed it up. + */ + virtio_reset_device_noirq(dev); + + /* Acknowledge that we've seen the device. */ + virtio_add_status_noirq(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE); + + /* + * Maybe driver failed before freeze. + * Restore the failed status, for debugging. + */ + if (dev->failed) + virtio_add_status_noirq(dev, VIRTIO_CONFIG_S_FAILED); + + if (!drv) + return 0; + + /* We have a driver! */ + virtio_add_status_noirq(dev, VIRTIO_CONFIG_S_DRIVER); + + ret =3D dev->config->finalize_features(dev); + if (ret) + return ret; + + return virtio_features_ok_noirq(dev); +} + #ifdef CONFIG_PM_SLEEP int virtio_device_freeze(struct virtio_device *dev) { @@ -627,6 +738,7 @@ int virtio_device_freeze(struct virtio_device *dev) virtio_config_core_disable(dev); =20 dev->failed =3D dev->config->get_status(dev) & VIRTIO_CONFIG_S_FAILED; + dev->noirq_restore_done =3D false; =20 if (drv && drv->freeze) { ret =3D drv->freeze(dev); @@ -645,12 +757,17 @@ int virtio_device_restore(struct virtio_device *dev) struct virtio_driver *drv =3D drv_to_virtio(dev->dev.driver); int ret; =20 - ret =3D virtio_device_reinit(dev); - if (ret) - goto err; - - if (!drv) - return 0; + /* + * If this device was already brought up in the noirq phase, + * skip the re-initialization here. + */ + if (!drv || !dev->noirq_restore_done) { + ret =3D virtio_device_reinit(dev); + if (ret) + goto err; + if (!drv) + return 0; + } =20 if (drv->restore) { ret =3D drv->restore(dev); @@ -671,6 +788,70 @@ int virtio_device_restore(struct virtio_device *dev) return ret; } EXPORT_SYMBOL_GPL(virtio_device_restore); + +int virtio_device_freeze_noirq(struct virtio_device *dev) +{ + struct virtio_driver *drv =3D drv_to_virtio(dev->dev.driver); + + if (drv && drv->freeze_noirq) { + /* + * If the driver provides restore_noirq and has active vqs, + * the transport must support reset_vqs to restore them. + * Fail here so the PM core can abort the transition + * gracefully, rather than hitting -EOPNOTSUPP on resume. + */ + if (drv->restore_noirq && !list_empty(&dev->vqs) && + !dev->config->reset_vqs) + return -EOPNOTSUPP; + + return drv->freeze_noirq(dev); + } + + return 0; +} +EXPORT_SYMBOL_GPL(virtio_device_freeze_noirq); + +int virtio_device_restore_noirq(struct virtio_device *dev) +{ + struct virtio_driver *drv =3D drv_to_virtio(dev->dev.driver); + int ret; + + if (!drv || !drv->restore_noirq) + return 0; + + ret =3D virtio_device_reinit_noirq(dev); + if (ret) + goto err; + + if (!list_empty(&dev->vqs)) { + if (!dev->config->reset_vqs) { + ret =3D -EOPNOTSUPP; + goto err; + } + + ret =3D dev->config->reset_vqs(dev); + if (ret) + goto err; + } + + ret =3D drv->restore_noirq(dev); + if (ret) + goto err; + + /* Mark that noirq restore has completed. */ + dev->noirq_restore_done =3D true; + + /* If restore_noirq set DRIVER_OK, enable config now. */ + if (dev->config->get_status(dev) & VIRTIO_CONFIG_S_DRIVER_OK) + virtio_config_core_enable_noirq(dev); + + return 0; + +err: + virtio_add_status_noirq(dev, VIRTIO_CONFIG_S_FAILED); + return ret; +} +EXPORT_SYMBOL_GPL(virtio_device_restore_noirq); #endif =20 int virtio_device_reset_prepare(struct virtio_device *dev) diff --git a/include/linux/virtio.h b/include/linux/virtio.h index 3bbc4cb6a672..ab66a3799310 100644 --- a/include/linux/virtio.h +++ b/include/linux/virtio.h @@ -151,6 +151,7 @@ struct virtio_admin_cmd { * @config_driver_disabled: configuration change reporting disabled by * a driver * @config_change_pending: configuration change reported while disabled + * @noirq_restore_done: set if the noirq restore phase completed successfu= lly * @config_lock: protects configuration change reporting * @vqs_list_lock: protects @vqs. * @dev: underlying device. @@ -171,6 +172,7 @@ struct virtio_device { bool config_core_enabled; bool config_driver_disabled; bool config_change_pending; + bool noirq_restore_done; spinlock_t config_lock; spinlock_t vqs_list_lock; struct device dev; @@ -209,8 +211,12 @@ void virtio_config_driver_enable(struct virtio_device = *dev); #ifdef CONFIG_PM_SLEEP int virtio_device_freeze(struct virtio_device *dev); int virtio_device_restore(struct virtio_device *dev); +int virtio_device_freeze_noirq(struct virtio_device *dev); +int virtio_device_restore_noirq(struct virtio_device *dev); #endif void virtio_reset_device(struct virtio_device *dev); +void virtio_reset_device_noirq(struct virtio_device *dev); +void virtio_add_status_noirq(struct virtio_device *dev, unsigned int statu= s); int virtio_device_reset_prepare(struct virtio_device *dev); int virtio_device_reset_done(struct virtio_device *dev); =20 @@ -237,6 +243,8 @@ size_t virtio_max_dma_size(const struct virtio_device *= vdev); * changes; may be called in interrupt context. * @freeze: optional function to call during suspend/hibernation. * @restore: optional function to call on resume. + * @freeze_noirq: optional function to call during noirq suspend/hibernati= on. + * @restore_noirq: optional function to call on noirq resume. * @reset_prepare: optional function to call when a transport specific res= et * occurs. * @reset_done: optional function to call after transport specific reset @@ -258,6 +266,8 @@ struct virtio_driver { void (*config_changed)(struct virtio_device *dev); int (*freeze)(struct virtio_device *dev); int (*restore)(struct virtio_device *dev); + int (*freeze_noirq)(struct virtio_device *dev); + int (*restore_noirq)(struct virtio_device *dev); int (*reset_prepare)(struct virtio_device *dev); int (*reset_done)(struct virtio_device *dev); void (*shutdown)(struct virtio_device *dev); diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index 69f84ea85d71..496897bc417e 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -70,6 +70,9 @@ struct virtqueue_info { * vqs_info: array of virtqueue info structures * Returns 0 on success or error status * @del_vqs: free virtqueues found by find_vqs(). + * @reset_vqs: reinitialize existing virtqueues without allocating or + * freeing them (optional). Used during noirq restore. + * Returns 0 on success or error status. * @synchronize_cbs: synchronize with the virtqueue callbacks (optional) * The function guarantees that all memory operations on the * queue before it are visible to the vring_interrupt() that is @@ -123,6 +126,7 @@ struct virtio_config_ops { struct virtqueue_info vqs_info[], struct irq_affinity *desc); void (*del_vqs)(struct virtio_device *); + int (*reset_vqs)(struct virtio_device *vdev); void (*synchronize_cbs)(struct virtio_device *); u64 (*get_features)(struct virtio_device *vdev); void (*get_extended_features)(struct virtio_device *vdev, @@ -371,6 +375,31 @@ void virtio_device_ready(struct virtio_device *dev) dev->config->set_status(dev, status | VIRTIO_CONFIG_S_DRIVER_OK); } =20 +/** + * virtio_device_ready_noirq - noirq-safe variant of virtio_device_ready() + * @dev: the virtio device + * + * This assumes that the device's get_status and set_status operations are + * noirq-safe. + */ +static inline +void virtio_device_ready_noirq(struct virtio_device *dev) +{ + unsigned int status =3D dev->config->get_status(dev); + + WARN_ON(status & VIRTIO_CONFIG_S_DRIVER_OK); + +#ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION + /* + * The noirq stage runs with device IRQ handlers disabled, so + * virtio_synchronize_cbs() must not be called here. + */ + __virtio_unbreak_device(dev); +#endif + + dev->config->set_status(dev, status | VIRTIO_CONFIG_S_DRIVER_OK); +} + static inline const char *virtio_bus_name(struct virtio_device *vdev) { --=20 2.43.0 From nobody Wed Jun 17 03:56:43 2026 Received: from mail-pj1-f47.google.com (mail-pj1-f47.google.com [209.85.216.47]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2C249367F58 for ; Wed, 22 Apr 2026 13:11:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776863469; cv=none; b=G6CRZjVgd6GAYKxBRp92J05vdPcL/wZsG4wfrEVpY5GyVl4wxAEu8CAv4gFZjrnOXGKk4Ww26wPFBbpwbFX5+ill4h+TygqT8Y41c554MiVEKdjhaBwzjgekThbxk7hL0s2BzvuUsS1dvI1bdPcFMhEqC57GVo5ptOyVo6EZoWY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776863469; c=relaxed/simple; bh=bqyZ3zlNX4wq0F4SlMToUsElYMW/0/3HtJhBt5GqWXw=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=QsnmfbO4ny8LcOEScyOxAEPxPCchlfhm4moZ1HHbzYKmy4a43Sz6gOR89FfNhJCCpiYJx6aqdqbB8tfgvYNJGJ9Vf2yO/NA1kG+YsIvUV7s6uIomYgcQfW699q2IGBYrGlZEelnzmjmJ80DY1BL2RrBVNjLaHzGQDAd379tyjmU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=hIum+VYL; arc=none smtp.client-ip=209.85.216.47 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="hIum+VYL" Received: by mail-pj1-f47.google.com with SMTP id 98e67ed59e1d1-356337f058aso3486212a91.2 for ; Wed, 22 Apr 2026 06:11:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1776863467; x=1777468267; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=kLZtjOym8UhPjw8gAAa2p99YiXwmHn7dLCASrBy1N7Y=; b=hIum+VYLpn9ms7lZs+D6qewZ77MStbzXd0l2Xgfl7b4wKKY0pPi5yYu5BmY57KgHJx YVnN8lml3uh3hUwFlR9aCzcMnPL9tJDzERhUkXRthotCve0jUcgDYv06Mnj4kShuTi3e CBpPeO/8UjZOa3PchEnY4nUssghUIY46/310ETpVwUGULYpPj6ppKwJ2rQMo8DfJshiK JWy0dCe6IaSbLOalD/eRC/ba94lHz+1QGtjSdoANeYzuR5uv6LEEOdlUl1gZIJf+zENE JKJvJlXOTCCmujVFj952BR1r28d+RUk2N2ScfWfUUn9aQWlrS2Tq6vdh5vOKSOHawITQ 9nHQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1776863467; x=1777468267; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=kLZtjOym8UhPjw8gAAa2p99YiXwmHn7dLCASrBy1N7Y=; b=aYOY6RnkiihrrmbeSr88SpEqbw/HmOl5Gtbj/Aac5PZs7RHdxFLRk0tq4Nw42DJDkQ CRVBTjE2vrN4HLSZYyVwWNEMCZ+r42puFz4pPOjI9jki7Y6CXulPZFSK1aQZogroWbYw c6+dFmsE2ZuXcBFQDGv6iu0DLcSU93VMxOzcThQJGAgLzX2g/RegHUnw7u5quD+niocY g45VoXGvYegO8ZuBbO0VPGTqcItAgKb4K1G4q2Pvvdj5mFljnMzQrgysnIE8rA0qZbfu UbcMfNLdfsSG+WTnsL7VRXI0Ys9qOeTaGcYW2ggxGCT96FlxS6UTngerSR8PGFHS1sIE 77uw== X-Forwarded-Encrypted: i=1; AFNElJ8nxCMa/TLxNgO6xNuVBCmMYMSufntCNMw7uQdcQJg3ZQC9HNtjOHqPtE7eb/ejkaQFNJdoO0j24Ynkwu8=@vger.kernel.org X-Gm-Message-State: AOJu0YydjhOG2mSvoIr2yLFmJC9uObBgYAYIYD1wLv4d532PnvCC98hU pcAU70t6vfYUYn7dstny6sa5kId5qNwmoQTeIpBKMbuvaQq3b7ZWm/Sg X-Gm-Gg: AeBDieuJs7WK4QREC6lMCxhy8SLi4kjhhhi3lq+zkNyn9+oxKvRc3i5CYVbO4jPXHG1 W1HCPnyd9lQQ/h0kTR8IRLCeti+3yKatuGd9I2DEYH9Xzqk1nlcvskvGs6l0vNoN7Gs5lMFTPrt PL2V1MtKVvvgHlmsM2T+cxZL1oGYjLkuftEU+ow6YwIBV3APkEz5VpFBp6ocvKnj0TxzpbbURSv phgJK0QWY/+4rddw89XavECQSWqHJWd26rZZPN1ikFTu2wEZwkgDa7tG6/xwfKvRI/taCmIENeN KARQc1AGDEYNtxLd7cRINzkJKs2phaztPdCokbIlQISr9P2L7+uTiyGeXEFdHms1cyBbD79gHIl Z1UMctBb4pXiVi7tknda2hLrreHWkTxrEIvqJAnsfz55ENm6BdHbKq20yXNrB6gZM9BcQ40wtZk fAiHVVXVZV/UtHMxllNWgkrh3loKYGGW1XywMcZYlj9LVEejk+4qtNUNkY5BgsUAy1HYRSo4grm n9udSb0HfCbeknbmTyq9+PBZMwOiNlNJFvQ/g== X-Received: by 2002:a17:903:3905:b0:2b0:7e4d:f43f with SMTP id d9443c01a7336-2b5f9ffe73amr214991645ad.41.1776863467453; Wed, 22 Apr 2026 06:11:07 -0700 (PDT) Received: from baver-zenith.localdomain ([124.49.88.131]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2b606ce9891sm127892235ad.83.2026.04.22.06.11.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 22 Apr 2026 06:11:07 -0700 (PDT) From: Sungho Bae To: mst@redhat.com, jasowang@redhat.com Cc: xuanzhuo@linux.alibaba.com, eperezma@redhat.com, virtualization@lists.linux.dev, linux-kernel@vger.kernel.org, Sungho Bae Subject: [RFC PATCH v3 4/4] virtio-mmio: wire up noirq system sleep PM callbacks Date: Wed, 22 Apr 2026 22:10:14 +0900 Message-Id: <20260422131014.956-5-baver.bae@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260422131014.956-1-baver.bae@gmail.com> References: <20260422131014.956-1-baver.bae@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Sungho Bae Implement the transport side of noirq system-sleep PM for virtio-mmio: - vm_reset_vqs(): iterate all virtqueues, call virtqueue_reinit_vring() to reset the vring state in place, then reprogram the MMIO queue registers (QUEUE_SEL, QUEUE_NUM, descriptor/avail/used addresses, QUEUE_READY) so the device can use the same rings immediately after restore. No memory is allocated or freed. - virtio_mmio_freeze_noirq() / virtio_mmio_restore_noirq(): thin wrappers that forward to the virtio core noirq helpers. The restore_noirq path also writes GUEST_PAGE_SIZE for legacy (v1) devices, matching the existing restore callback. - Wire vm_reset_vqs into virtio_mmio_config_ops and register the noirq callbacks via SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(). With this in place, a virtio-mmio driver can implement freeze_noirq / restore_noirq to participate in the noirq PM phase, enabling use cases such as virtio-clock or virtio-regulator that must be operational before other devices are restored. Signed-off-by: Sungho Bae --- drivers/virtio/virtio_mmio.c | 133 ++++++++++++++++++++++++----------- 1 file changed, 93 insertions(+), 40 deletions(-) diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c index 595c2274fbb5..583da43013e7 100644 --- a/drivers/virtio/virtio_mmio.c +++ b/drivers/virtio/virtio_mmio.c @@ -336,6 +336,75 @@ static void vm_del_vqs(struct virtio_device *vdev) free_irq(platform_get_irq(vm_dev->pdev, 0), vm_dev); } =20 +static int vm_active_vq(struct virtio_device *vdev, struct virtqueue *vq) +{ + struct virtio_mmio_device *vm_dev =3D to_virtio_mmio_device(vdev); + int q_num =3D virtqueue_get_vring_size(vq); + + writel(q_num, vm_dev->base + VIRTIO_MMIO_QUEUE_NUM); + if (vm_dev->version =3D=3D 1) { + u64 q_pfn =3D virtqueue_get_desc_addr(vq) >> PAGE_SHIFT; + + /* + * virtio-mmio v1 uses a 32bit QUEUE PFN. If we have something + * that doesn't fit in 32bit, fail the setup rather than + * pretending to be successful. + */ + if (q_pfn >> 32) { + dev_err(&vdev->dev, + "platform bug: legacy virtio-mmio must not be used with RAM above 0x%l= lxGB\n", + 0x1ULL << (32 + PAGE_SHIFT - 30)); + return -E2BIG; + } + + writel(PAGE_SIZE, vm_dev->base + VIRTIO_MMIO_QUEUE_ALIGN); + writel(q_pfn, vm_dev->base + VIRTIO_MMIO_QUEUE_PFN); + } else { + u64 addr; + + addr =3D virtqueue_get_desc_addr(vq); + writel((u32)addr, vm_dev->base + VIRTIO_MMIO_QUEUE_DESC_LOW); + writel((u32)(addr >> 32), + vm_dev->base + VIRTIO_MMIO_QUEUE_DESC_HIGH); + + addr =3D virtqueue_get_avail_addr(vq); + writel((u32)addr, vm_dev->base + VIRTIO_MMIO_QUEUE_AVAIL_LOW); + writel((u32)(addr >> 32), + vm_dev->base + VIRTIO_MMIO_QUEUE_AVAIL_HIGH); + + addr =3D virtqueue_get_used_addr(vq); + writel((u32)addr, vm_dev->base + VIRTIO_MMIO_QUEUE_USED_LOW); + writel((u32)(addr >> 32), + vm_dev->base + VIRTIO_MMIO_QUEUE_USED_HIGH); + + writel(1, vm_dev->base + VIRTIO_MMIO_QUEUE_READY); + } + + return 0; +} + +static int vm_reset_vqs(struct virtio_device *vdev) +{ + struct virtio_mmio_device *vm_dev =3D to_virtio_mmio_device(vdev); + struct virtqueue *vq; + int err; + + virtio_device_for_each_vq(vdev, vq) { + /* Re-initialize vring state */ + virtqueue_reinit_vring(vq); + + /* Select the queue we're interested in */ + writel(vq->index, vm_dev->base + VIRTIO_MMIO_QUEUE_SEL); + + /* Activate the queue */ + err =3D vm_active_vq(vdev, vq); + if (err < 0) + return err; + } + + return 0; +} + static void vm_synchronize_cbs(struct virtio_device *vdev) { struct virtio_mmio_device *vm_dev =3D to_virtio_mmio_device(vdev); @@ -388,45 +457,9 @@ static struct virtqueue *vm_setup_vq(struct virtio_dev= ice *vdev, unsigned int in vq->num_max =3D num; =20 /* Activate the queue */ - writel(virtqueue_get_vring_size(vq), vm_dev->base + VIRTIO_MMIO_QUEUE_NUM= ); - if (vm_dev->version =3D=3D 1) { - u64 q_pfn =3D virtqueue_get_desc_addr(vq) >> PAGE_SHIFT; - - /* - * virtio-mmio v1 uses a 32bit QUEUE PFN. If we have something - * that doesn't fit in 32bit, fail the setup rather than - * pretending to be successful. - */ - if (q_pfn >> 32) { - dev_err(&vdev->dev, - "platform bug: legacy virtio-mmio must not be used with RAM above 0x%l= lxGB\n", - 0x1ULL << (32 + PAGE_SHIFT - 30)); - err =3D -E2BIG; - goto error_bad_pfn; - } - - writel(PAGE_SIZE, vm_dev->base + VIRTIO_MMIO_QUEUE_ALIGN); - writel(q_pfn, vm_dev->base + VIRTIO_MMIO_QUEUE_PFN); - } else { - u64 addr; - - addr =3D virtqueue_get_desc_addr(vq); - writel((u32)addr, vm_dev->base + VIRTIO_MMIO_QUEUE_DESC_LOW); - writel((u32)(addr >> 32), - vm_dev->base + VIRTIO_MMIO_QUEUE_DESC_HIGH); - - addr =3D virtqueue_get_avail_addr(vq); - writel((u32)addr, vm_dev->base + VIRTIO_MMIO_QUEUE_AVAIL_LOW); - writel((u32)(addr >> 32), - vm_dev->base + VIRTIO_MMIO_QUEUE_AVAIL_HIGH); - - addr =3D virtqueue_get_used_addr(vq); - writel((u32)addr, vm_dev->base + VIRTIO_MMIO_QUEUE_USED_LOW); - writel((u32)(addr >> 32), - vm_dev->base + VIRTIO_MMIO_QUEUE_USED_HIGH); - - writel(1, vm_dev->base + VIRTIO_MMIO_QUEUE_READY); - } + err =3D vm_active_vq(vdev, vq); + if (err < 0) + goto error_bad_pfn; =20 return vq; =20 @@ -528,6 +561,7 @@ static const struct virtio_config_ops virtio_mmio_confi= g_ops =3D { .reset =3D vm_reset, .find_vqs =3D vm_find_vqs, .del_vqs =3D vm_del_vqs, + .reset_vqs =3D vm_reset_vqs, .get_features =3D vm_get_features, .finalize_features =3D vm_finalize_features, .bus_name =3D vm_bus_name, @@ -547,14 +581,33 @@ static int virtio_mmio_restore(struct device *dev) { struct virtio_mmio_device *vm_dev =3D dev_get_drvdata(dev); =20 - if (vm_dev->version =3D=3D 1) + if (vm_dev->version =3D=3D 1 && !vm_dev->vdev.noirq_restore_done) writel(PAGE_SIZE, vm_dev->base + VIRTIO_MMIO_GUEST_PAGE_SIZE); =20 return virtio_device_restore(&vm_dev->vdev); } =20 +static int virtio_mmio_freeze_noirq(struct device *dev) +{ + struct virtio_mmio_device *vm_dev =3D dev_get_drvdata(dev); + + return virtio_device_freeze_noirq(&vm_dev->vdev); +} + +static int virtio_mmio_restore_noirq(struct device *dev) +{ + struct virtio_mmio_device *vm_dev =3D dev_get_drvdata(dev); + + if (vm_dev->version =3D=3D 1) + writel(PAGE_SIZE, vm_dev->base + VIRTIO_MMIO_GUEST_PAGE_SIZE); + + return virtio_device_restore_noirq(&vm_dev->vdev); +} + static const struct dev_pm_ops virtio_mmio_pm_ops =3D { SET_SYSTEM_SLEEP_PM_OPS(virtio_mmio_freeze, virtio_mmio_restore) + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(virtio_mmio_freeze_noirq, + virtio_mmio_restore_noirq) }; #endif =20 --=20 2.43.0