Skip to content

Commit a0ec4fb

Browse files
israelrumstsirkin
authored andcommitted
virtio_pci: Add support for PCIe Function Level Reset
Implement support for Function Level Reset (FLR) in virtio_pci devices. This change adds reset_prepare and reset_done callbacks, allowing drivers to properly handle FLR operations. Without this patch, performing and recovering from an FLR is not possible for virtio_pci devices. This implementation ensures proper FLR handling and recovery for both physical and virtual functions. The device reset can be triggered in case of error or manually via sysfs: echo 1 > /sys/bus/pci/devices/$PCI_ADDR/reset Signed-off-by: Israel Rukshin <[email protected]> Reviewed-by: Max Gurtovoy <[email protected]> Message-Id: <[email protected]> Signed-off-by: Michael S. Tsirkin <[email protected]>
1 parent a3b9c05 commit a0ec4fb

File tree

3 files changed

+118
-25
lines changed

3 files changed

+118
-25
lines changed

drivers/virtio/virtio.c

Lines changed: 69 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -527,29 +527,7 @@ void unregister_virtio_device(struct virtio_device *dev)
527527
}
528528
EXPORT_SYMBOL_GPL(unregister_virtio_device);
529529

530-
#ifdef CONFIG_PM_SLEEP
531-
int virtio_device_freeze(struct virtio_device *dev)
532-
{
533-
struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
534-
int ret;
535-
536-
virtio_config_core_disable(dev);
537-
538-
dev->failed = dev->config->get_status(dev) & VIRTIO_CONFIG_S_FAILED;
539-
540-
if (drv && drv->freeze) {
541-
ret = drv->freeze(dev);
542-
if (ret) {
543-
virtio_config_core_enable(dev);
544-
return ret;
545-
}
546-
}
547-
548-
return 0;
549-
}
550-
EXPORT_SYMBOL_GPL(virtio_device_freeze);
551-
552-
int virtio_device_restore(struct virtio_device *dev)
530+
static int virtio_device_restore_priv(struct virtio_device *dev, bool restore)
553531
{
554532
struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
555533
int ret;
@@ -580,8 +558,14 @@ int virtio_device_restore(struct virtio_device *dev)
580558
if (ret)
581559
goto err;
582560

583-
if (drv->restore) {
584-
ret = drv->restore(dev);
561+
if (restore) {
562+
if (drv->restore) {
563+
ret = drv->restore(dev);
564+
if (ret)
565+
goto err;
566+
}
567+
} else {
568+
ret = drv->reset_done(dev);
585569
if (ret)
586570
goto err;
587571
}
@@ -598,9 +582,69 @@ int virtio_device_restore(struct virtio_device *dev)
598582
virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED);
599583
return ret;
600584
}
585+
586+
#ifdef CONFIG_PM_SLEEP
587+
int virtio_device_freeze(struct virtio_device *dev)
588+
{
589+
struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
590+
int ret;
591+
592+
virtio_config_core_disable(dev);
593+
594+
dev->failed = dev->config->get_status(dev) & VIRTIO_CONFIG_S_FAILED;
595+
596+
if (drv && drv->freeze) {
597+
ret = drv->freeze(dev);
598+
if (ret) {
599+
virtio_config_core_enable(dev);
600+
return ret;
601+
}
602+
}
603+
604+
return 0;
605+
}
606+
EXPORT_SYMBOL_GPL(virtio_device_freeze);
607+
608+
int virtio_device_restore(struct virtio_device *dev)
609+
{
610+
return virtio_device_restore_priv(dev, true);
611+
}
601612
EXPORT_SYMBOL_GPL(virtio_device_restore);
602613
#endif
603614

615+
int virtio_device_reset_prepare(struct virtio_device *dev)
616+
{
617+
struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
618+
int ret;
619+
620+
if (!drv || !drv->reset_prepare)
621+
return -EOPNOTSUPP;
622+
623+
virtio_config_core_disable(dev);
624+
625+
dev->failed = dev->config->get_status(dev) & VIRTIO_CONFIG_S_FAILED;
626+
627+
ret = drv->reset_prepare(dev);
628+
if (ret) {
629+
virtio_config_core_enable(dev);
630+
return ret;
631+
}
632+
633+
return 0;
634+
}
635+
EXPORT_SYMBOL_GPL(virtio_device_reset_prepare);
636+
637+
int virtio_device_reset_done(struct virtio_device *dev)
638+
{
639+
struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
640+
641+
if (!drv || !drv->reset_done)
642+
return -EOPNOTSUPP;
643+
644+
return virtio_device_restore_priv(dev, false);
645+
}
646+
EXPORT_SYMBOL_GPL(virtio_device_reset_done);
647+
604648
static int virtio_init(void)
605649
{
606650
if (bus_register(&virtio_bus) != 0)

drivers/virtio/virtio_pci_common.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,46 @@ static int virtio_pci_sriov_configure(struct pci_dev *pci_dev, int num_vfs)
794794
return num_vfs;
795795
}
796796

797+
static void virtio_pci_reset_prepare(struct pci_dev *pci_dev)
798+
{
799+
struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
800+
int ret = 0;
801+
802+
ret = virtio_device_reset_prepare(&vp_dev->vdev);
803+
if (ret) {
804+
if (ret != -EOPNOTSUPP)
805+
dev_warn(&pci_dev->dev, "Reset prepare failure: %d",
806+
ret);
807+
return;
808+
}
809+
810+
if (pci_is_enabled(pci_dev))
811+
pci_disable_device(pci_dev);
812+
}
813+
814+
static void virtio_pci_reset_done(struct pci_dev *pci_dev)
815+
{
816+
struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
817+
int ret;
818+
819+
if (pci_is_enabled(pci_dev))
820+
return;
821+
822+
ret = pci_enable_device(pci_dev);
823+
if (!ret) {
824+
pci_set_master(pci_dev);
825+
ret = virtio_device_reset_done(&vp_dev->vdev);
826+
}
827+
828+
if (ret && ret != -EOPNOTSUPP)
829+
dev_warn(&pci_dev->dev, "Reset done failure: %d", ret);
830+
}
831+
832+
static const struct pci_error_handlers virtio_pci_err_handler = {
833+
.reset_prepare = virtio_pci_reset_prepare,
834+
.reset_done = virtio_pci_reset_done,
835+
};
836+
797837
static struct pci_driver virtio_pci_driver = {
798838
.name = "virtio-pci",
799839
.id_table = virtio_pci_id_table,
@@ -803,6 +843,7 @@ static struct pci_driver virtio_pci_driver = {
803843
.driver.pm = &virtio_pci_pm_ops,
804844
#endif
805845
.sriov_configure = virtio_pci_sriov_configure,
846+
.err_handler = &virtio_pci_err_handler,
806847
};
807848

808849
struct virtio_device *virtio_pci_vf_get_pf_dev(struct pci_dev *pdev)

include/linux/virtio.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,8 @@ int virtio_device_freeze(struct virtio_device *dev);
190190
int virtio_device_restore(struct virtio_device *dev);
191191
#endif
192192
void virtio_reset_device(struct virtio_device *dev);
193+
int virtio_device_reset_prepare(struct virtio_device *dev);
194+
int virtio_device_reset_done(struct virtio_device *dev);
193195

194196
size_t virtio_max_dma_size(const struct virtio_device *vdev);
195197

@@ -214,6 +216,10 @@ size_t virtio_max_dma_size(const struct virtio_device *vdev);
214216
* changes; may be called in interrupt context.
215217
* @freeze: optional function to call during suspend/hibernation.
216218
* @restore: optional function to call on resume.
219+
* @reset_prepare: optional function to call when a transport specific reset
220+
* occurs.
221+
* @reset_done: optional function to call after transport specific reset
222+
* operation has finished.
217223
*/
218224
struct virtio_driver {
219225
struct device_driver driver;
@@ -229,6 +235,8 @@ struct virtio_driver {
229235
void (*config_changed)(struct virtio_device *dev);
230236
int (*freeze)(struct virtio_device *dev);
231237
int (*restore)(struct virtio_device *dev);
238+
int (*reset_prepare)(struct virtio_device *dev);
239+
int (*reset_done)(struct virtio_device *dev);
232240
};
233241

234242
#define drv_to_virtio(__drv) container_of_const(__drv, struct virtio_driver, driver)

0 commit comments

Comments
 (0)