Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

um: virtio/pci: enable suspend/resume

The UM virtual PCI devices currently cannot be suspended properly
since the virtio driver already disables VQs well before the PCI
bus's suspend_noirq wants to complete the transition by writing to
PCI config space.

After trying around for a long time with moving the devices on the
DPM list, trying to create dependencies between them, etc. I gave
up and instead added UML specific cross-driver API that lets the
virt-pci code enable not suspending/resuming VQs for its devices.

This then allows the PCI bus suspend_noirq to still talk to the
device, and suspend/resume works properly.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Richard Weinberger <richard@nod.at>

authored by

Johannes Berg and committed by
Richard Weinberger
43c590cb 68f5d3f3

+53 -10
+10
arch/um/drivers/virt-pci.c
··· 10 10 #include <linux/logic_iomem.h> 11 11 #include <linux/irqdomain.h> 12 12 #include <linux/virtio_pcidev.h> 13 + #include <linux/virtio-uml.h> 13 14 #include <linux/delay.h> 14 15 #include <linux/msi.h> 15 16 #include <asm/unaligned.h> ··· 134 133 135 134 if (completed == HANDLE_NO_FREE(cmd)) 136 135 break; 136 + 137 + if (completed && !HANDLE_IS_NO_FREE(completed)) 138 + kfree(completed); 137 139 138 140 if (WARN_ONCE(virtqueue_is_broken(dev->cmd_vq) || 139 141 ++delay_count > UM_VIRT_PCI_MAXDELAY, ··· 553 549 mutex_unlock(&um_pci_mtx); 554 550 555 551 device_set_wakeup_enable(&vdev->dev, true); 552 + 553 + /* 554 + * In order to do suspend-resume properly, don't allow VQs 555 + * to be suspended. 556 + */ 557 + virtio_uml_set_no_vq_suspend(vdev, true); 556 558 557 559 um_pci_rescan(); 558 560 return 0;
+30 -10
arch/um/drivers/virtio_uml.c
··· 56 56 u8 status; 57 57 u8 registered:1; 58 58 u8 suspended:1; 59 + u8 no_vq_suspend:1; 59 60 60 61 u8 config_changed_irq:1; 61 62 uint64_t vq_irq_vq_map; ··· 1099 1098 kfree(vu_dev); 1100 1099 } 1101 1100 1101 + void virtio_uml_set_no_vq_suspend(struct virtio_device *vdev, 1102 + bool no_vq_suspend) 1103 + { 1104 + struct virtio_uml_device *vu_dev = to_virtio_uml_device(vdev); 1105 + 1106 + if (WARN_ON(vdev->config != &virtio_uml_config_ops)) 1107 + return; 1108 + 1109 + vu_dev->no_vq_suspend = no_vq_suspend; 1110 + dev_info(&vdev->dev, "%sabled VQ suspend\n", 1111 + no_vq_suspend ? "dis" : "en"); 1112 + } 1113 + 1102 1114 /* Platform device */ 1103 1115 1104 1116 static int virtio_uml_probe(struct platform_device *pdev) ··· 1316 1302 static int virtio_uml_suspend(struct platform_device *pdev, pm_message_t state) 1317 1303 { 1318 1304 struct virtio_uml_device *vu_dev = platform_get_drvdata(pdev); 1319 - struct virtqueue *vq; 1320 1305 1321 - virtio_device_for_each_vq((&vu_dev->vdev), vq) { 1322 - struct virtio_uml_vq_info *info = vq->priv; 1306 + if (!vu_dev->no_vq_suspend) { 1307 + struct virtqueue *vq; 1323 1308 1324 - info->suspended = true; 1325 - vhost_user_set_vring_enable(vu_dev, vq->index, false); 1309 + virtio_device_for_each_vq((&vu_dev->vdev), vq) { 1310 + struct virtio_uml_vq_info *info = vq->priv; 1311 + 1312 + info->suspended = true; 1313 + vhost_user_set_vring_enable(vu_dev, vq->index, false); 1314 + } 1326 1315 } 1327 1316 1328 1317 if (!device_may_wakeup(&vu_dev->vdev.dev)) { ··· 1339 1322 static int virtio_uml_resume(struct platform_device *pdev) 1340 1323 { 1341 1324 struct virtio_uml_device *vu_dev = platform_get_drvdata(pdev); 1342 - struct virtqueue *vq; 1343 1325 1344 - virtio_device_for_each_vq((&vu_dev->vdev), vq) { 1345 - struct virtio_uml_vq_info *info = vq->priv; 1326 + if (!vu_dev->no_vq_suspend) { 1327 + struct virtqueue *vq; 1346 1328 1347 - info->suspended = false; 1348 - vhost_user_set_vring_enable(vu_dev, vq->index, true); 1329 + virtio_device_for_each_vq((&vu_dev->vdev), vq) { 1330 + struct virtio_uml_vq_info *info = vq->priv; 1331 + 1332 + info->suspended = false; 1333 + vhost_user_set_vring_enable(vu_dev, vq->index, true); 1334 + } 1349 1335 } 1350 1336 1351 1337 vu_dev->suspended = false;
+13
arch/um/include/linux/virtio-uml.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (C) 2021 Intel Corporation 4 + * Author: Johannes Berg <johannes@sipsolutions.net> 5 + */ 6 + 7 + #ifndef __VIRTIO_UML_H__ 8 + #define __VIRTIO_UML_H__ 9 + 10 + void virtio_uml_set_no_vq_suspend(struct virtio_device *vdev, 11 + bool no_vq_suspend); 12 + 13 + #endif /* __VIRTIO_UML_H__ */