mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git
synced 2026-05-02 18:17:50 -04:00
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 <israelr@nvidia.com> Reviewed-by: Max Gurtovoy <mgurtovoy@nvidia.com> Message-Id: <1732690652-3065-2-git-send-email-israelr@nvidia.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
committed by
Michael S. Tsirkin
parent
a3b9c053d8
commit
a0ec4fb63f
@@ -527,29 +527,7 @@ void unregister_virtio_device(struct virtio_device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(unregister_virtio_device);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
int virtio_device_freeze(struct virtio_device *dev)
|
||||
{
|
||||
struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
|
||||
int ret;
|
||||
|
||||
virtio_config_core_disable(dev);
|
||||
|
||||
dev->failed = dev->config->get_status(dev) & VIRTIO_CONFIG_S_FAILED;
|
||||
|
||||
if (drv && drv->freeze) {
|
||||
ret = drv->freeze(dev);
|
||||
if (ret) {
|
||||
virtio_config_core_enable(dev);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(virtio_device_freeze);
|
||||
|
||||
int virtio_device_restore(struct virtio_device *dev)
|
||||
static int virtio_device_restore_priv(struct virtio_device *dev, bool restore)
|
||||
{
|
||||
struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
|
||||
int ret;
|
||||
@@ -580,8 +558,14 @@ int virtio_device_restore(struct virtio_device *dev)
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
if (drv->restore) {
|
||||
ret = drv->restore(dev);
|
||||
if (restore) {
|
||||
if (drv->restore) {
|
||||
ret = drv->restore(dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
ret = drv->reset_done(dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
@@ -598,9 +582,69 @@ err:
|
||||
virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
int virtio_device_freeze(struct virtio_device *dev)
|
||||
{
|
||||
struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
|
||||
int ret;
|
||||
|
||||
virtio_config_core_disable(dev);
|
||||
|
||||
dev->failed = dev->config->get_status(dev) & VIRTIO_CONFIG_S_FAILED;
|
||||
|
||||
if (drv && drv->freeze) {
|
||||
ret = drv->freeze(dev);
|
||||
if (ret) {
|
||||
virtio_config_core_enable(dev);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(virtio_device_freeze);
|
||||
|
||||
int virtio_device_restore(struct virtio_device *dev)
|
||||
{
|
||||
return virtio_device_restore_priv(dev, true);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(virtio_device_restore);
|
||||
#endif
|
||||
|
||||
int virtio_device_reset_prepare(struct virtio_device *dev)
|
||||
{
|
||||
struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
|
||||
int ret;
|
||||
|
||||
if (!drv || !drv->reset_prepare)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
virtio_config_core_disable(dev);
|
||||
|
||||
dev->failed = dev->config->get_status(dev) & VIRTIO_CONFIG_S_FAILED;
|
||||
|
||||
ret = drv->reset_prepare(dev);
|
||||
if (ret) {
|
||||
virtio_config_core_enable(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(virtio_device_reset_prepare);
|
||||
|
||||
int virtio_device_reset_done(struct virtio_device *dev)
|
||||
{
|
||||
struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
|
||||
|
||||
if (!drv || !drv->reset_done)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return virtio_device_restore_priv(dev, false);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(virtio_device_reset_done);
|
||||
|
||||
static int virtio_init(void)
|
||||
{
|
||||
if (bus_register(&virtio_bus) != 0)
|
||||
|
||||
@@ -794,6 +794,46 @@ static int virtio_pci_sriov_configure(struct pci_dev *pci_dev, int num_vfs)
|
||||
return num_vfs;
|
||||
}
|
||||
|
||||
static void virtio_pci_reset_prepare(struct pci_dev *pci_dev)
|
||||
{
|
||||
struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
|
||||
int ret = 0;
|
||||
|
||||
ret = virtio_device_reset_prepare(&vp_dev->vdev);
|
||||
if (ret) {
|
||||
if (ret != -EOPNOTSUPP)
|
||||
dev_warn(&pci_dev->dev, "Reset prepare failure: %d",
|
||||
ret);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pci_is_enabled(pci_dev))
|
||||
pci_disable_device(pci_dev);
|
||||
}
|
||||
|
||||
static void virtio_pci_reset_done(struct pci_dev *pci_dev)
|
||||
{
|
||||
struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
|
||||
int ret;
|
||||
|
||||
if (pci_is_enabled(pci_dev))
|
||||
return;
|
||||
|
||||
ret = pci_enable_device(pci_dev);
|
||||
if (!ret) {
|
||||
pci_set_master(pci_dev);
|
||||
ret = virtio_device_reset_done(&vp_dev->vdev);
|
||||
}
|
||||
|
||||
if (ret && ret != -EOPNOTSUPP)
|
||||
dev_warn(&pci_dev->dev, "Reset done failure: %d", ret);
|
||||
}
|
||||
|
||||
static const struct pci_error_handlers virtio_pci_err_handler = {
|
||||
.reset_prepare = virtio_pci_reset_prepare,
|
||||
.reset_done = virtio_pci_reset_done,
|
||||
};
|
||||
|
||||
static struct pci_driver virtio_pci_driver = {
|
||||
.name = "virtio-pci",
|
||||
.id_table = virtio_pci_id_table,
|
||||
@@ -803,6 +843,7 @@ static struct pci_driver virtio_pci_driver = {
|
||||
.driver.pm = &virtio_pci_pm_ops,
|
||||
#endif
|
||||
.sriov_configure = virtio_pci_sriov_configure,
|
||||
.err_handler = &virtio_pci_err_handler,
|
||||
};
|
||||
|
||||
struct virtio_device *virtio_pci_vf_get_pf_dev(struct pci_dev *pdev)
|
||||
|
||||
Reference in New Issue
Block a user