vfio/pci: Move to the device set infrastructure
PCI wants to have the usual open/close_device() logic with the slight twist that the open/close_device() must be done under a singelton lock shared by all of the vfio_devices that are in the PCI "reset group". The reset group, and thus the device set, is determined by what devices pci_reset_bus() touches, which is either the entire bus or only the slot. Rely on the core code to do everything reflck was doing and delete reflck entirely. Signed-off-by: Yishai Hadas <yishaih@nvidia.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com> Reviewed-by: Cornelia Huck <cohuck@redhat.com> Link: https://lore.kernel.org/r/8-v4-9ea22c5e6afb+1adf-vfio_reflck_jgg@nvidia.com Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
This commit is contained in:
parent
ab7e5e34a9
commit
2cd8b14aaa
@ -530,53 +530,40 @@ static void vfio_pci_vf_token_user_add(struct vfio_pci_device *vdev, int val)
|
|||||||
vfio_device_put(&pf_vdev->vdev);
|
vfio_device_put(&pf_vdev->vdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vfio_pci_release(struct vfio_device *core_vdev)
|
static void vfio_pci_close_device(struct vfio_device *core_vdev)
|
||||||
{
|
{
|
||||||
struct vfio_pci_device *vdev =
|
struct vfio_pci_device *vdev =
|
||||||
container_of(core_vdev, struct vfio_pci_device, vdev);
|
container_of(core_vdev, struct vfio_pci_device, vdev);
|
||||||
|
|
||||||
mutex_lock(&vdev->reflck->lock);
|
vfio_pci_vf_token_user_add(vdev, -1);
|
||||||
|
vfio_spapr_pci_eeh_release(vdev->pdev);
|
||||||
|
vfio_pci_disable(vdev);
|
||||||
|
|
||||||
if (!(--vdev->refcnt)) {
|
mutex_lock(&vdev->igate);
|
||||||
vfio_pci_vf_token_user_add(vdev, -1);
|
if (vdev->err_trigger) {
|
||||||
vfio_spapr_pci_eeh_release(vdev->pdev);
|
eventfd_ctx_put(vdev->err_trigger);
|
||||||
vfio_pci_disable(vdev);
|
vdev->err_trigger = NULL;
|
||||||
|
|
||||||
mutex_lock(&vdev->igate);
|
|
||||||
if (vdev->err_trigger) {
|
|
||||||
eventfd_ctx_put(vdev->err_trigger);
|
|
||||||
vdev->err_trigger = NULL;
|
|
||||||
}
|
|
||||||
if (vdev->req_trigger) {
|
|
||||||
eventfd_ctx_put(vdev->req_trigger);
|
|
||||||
vdev->req_trigger = NULL;
|
|
||||||
}
|
|
||||||
mutex_unlock(&vdev->igate);
|
|
||||||
}
|
}
|
||||||
|
if (vdev->req_trigger) {
|
||||||
mutex_unlock(&vdev->reflck->lock);
|
eventfd_ctx_put(vdev->req_trigger);
|
||||||
|
vdev->req_trigger = NULL;
|
||||||
|
}
|
||||||
|
mutex_unlock(&vdev->igate);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vfio_pci_open(struct vfio_device *core_vdev)
|
static int vfio_pci_open_device(struct vfio_device *core_vdev)
|
||||||
{
|
{
|
||||||
struct vfio_pci_device *vdev =
|
struct vfio_pci_device *vdev =
|
||||||
container_of(core_vdev, struct vfio_pci_device, vdev);
|
container_of(core_vdev, struct vfio_pci_device, vdev);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
mutex_lock(&vdev->reflck->lock);
|
ret = vfio_pci_enable(vdev);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
if (!vdev->refcnt) {
|
vfio_spapr_pci_eeh_open(vdev->pdev);
|
||||||
ret = vfio_pci_enable(vdev);
|
vfio_pci_vf_token_user_add(vdev, 1);
|
||||||
if (ret)
|
return 0;
|
||||||
goto error;
|
|
||||||
|
|
||||||
vfio_spapr_pci_eeh_open(vdev->pdev);
|
|
||||||
vfio_pci_vf_token_user_add(vdev, 1);
|
|
||||||
}
|
|
||||||
vdev->refcnt++;
|
|
||||||
error:
|
|
||||||
mutex_unlock(&vdev->reflck->lock);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vfio_pci_get_irq_count(struct vfio_pci_device *vdev, int irq_type)
|
static int vfio_pci_get_irq_count(struct vfio_pci_device *vdev, int irq_type)
|
||||||
@ -1870,8 +1857,8 @@ static int vfio_pci_match(struct vfio_device *core_vdev, char *buf)
|
|||||||
|
|
||||||
static const struct vfio_device_ops vfio_pci_ops = {
|
static const struct vfio_device_ops vfio_pci_ops = {
|
||||||
.name = "vfio-pci",
|
.name = "vfio-pci",
|
||||||
.open = vfio_pci_open,
|
.open_device = vfio_pci_open_device,
|
||||||
.release = vfio_pci_release,
|
.close_device = vfio_pci_close_device,
|
||||||
.ioctl = vfio_pci_ioctl,
|
.ioctl = vfio_pci_ioctl,
|
||||||
.read = vfio_pci_read,
|
.read = vfio_pci_read,
|
||||||
.write = vfio_pci_write,
|
.write = vfio_pci_write,
|
||||||
@ -1880,9 +1867,6 @@ static const struct vfio_device_ops vfio_pci_ops = {
|
|||||||
.match = vfio_pci_match,
|
.match = vfio_pci_match,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int vfio_pci_reflck_attach(struct vfio_pci_device *vdev);
|
|
||||||
static void vfio_pci_reflck_put(struct vfio_pci_reflck *reflck);
|
|
||||||
|
|
||||||
static int vfio_pci_bus_notifier(struct notifier_block *nb,
|
static int vfio_pci_bus_notifier(struct notifier_block *nb,
|
||||||
unsigned long action, void *data)
|
unsigned long action, void *data)
|
||||||
{
|
{
|
||||||
@ -2020,12 +2004,23 @@ static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||||||
INIT_LIST_HEAD(&vdev->vma_list);
|
INIT_LIST_HEAD(&vdev->vma_list);
|
||||||
init_rwsem(&vdev->memory_lock);
|
init_rwsem(&vdev->memory_lock);
|
||||||
|
|
||||||
ret = vfio_pci_reflck_attach(vdev);
|
if (pci_is_root_bus(pdev->bus)) {
|
||||||
|
ret = vfio_assign_device_set(&vdev->vdev, vdev);
|
||||||
|
} else if (!pci_probe_reset_slot(pdev->slot)) {
|
||||||
|
ret = vfio_assign_device_set(&vdev->vdev, pdev->slot);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* If there is no slot reset support for this device, the whole
|
||||||
|
* bus needs to be grouped together to support bus-wide resets.
|
||||||
|
*/
|
||||||
|
ret = vfio_assign_device_set(&vdev->vdev, pdev->bus);
|
||||||
|
}
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_uninit;
|
goto out_uninit;
|
||||||
ret = vfio_pci_vf_init(vdev);
|
ret = vfio_pci_vf_init(vdev);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_reflck;
|
goto out_uninit;
|
||||||
ret = vfio_pci_vga_init(vdev);
|
ret = vfio_pci_vga_init(vdev);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_vf;
|
goto out_vf;
|
||||||
@ -2057,8 +2052,6 @@ out_power:
|
|||||||
vfio_pci_set_power_state(vdev, PCI_D0);
|
vfio_pci_set_power_state(vdev, PCI_D0);
|
||||||
out_vf:
|
out_vf:
|
||||||
vfio_pci_vf_uninit(vdev);
|
vfio_pci_vf_uninit(vdev);
|
||||||
out_reflck:
|
|
||||||
vfio_pci_reflck_put(vdev->reflck);
|
|
||||||
out_uninit:
|
out_uninit:
|
||||||
vfio_uninit_group_dev(&vdev->vdev);
|
vfio_uninit_group_dev(&vdev->vdev);
|
||||||
kfree(vdev->pm_save);
|
kfree(vdev->pm_save);
|
||||||
@ -2077,7 +2070,6 @@ static void vfio_pci_remove(struct pci_dev *pdev)
|
|||||||
vfio_unregister_group_dev(&vdev->vdev);
|
vfio_unregister_group_dev(&vdev->vdev);
|
||||||
|
|
||||||
vfio_pci_vf_uninit(vdev);
|
vfio_pci_vf_uninit(vdev);
|
||||||
vfio_pci_reflck_put(vdev->reflck);
|
|
||||||
vfio_uninit_group_dev(&vdev->vdev);
|
vfio_uninit_group_dev(&vdev->vdev);
|
||||||
vfio_pci_vga_uninit(vdev);
|
vfio_pci_vga_uninit(vdev);
|
||||||
|
|
||||||
@ -2153,86 +2145,6 @@ static struct pci_driver vfio_pci_driver = {
|
|||||||
.err_handler = &vfio_err_handlers,
|
.err_handler = &vfio_err_handlers,
|
||||||
};
|
};
|
||||||
|
|
||||||
static DEFINE_MUTEX(reflck_lock);
|
|
||||||
|
|
||||||
static struct vfio_pci_reflck *vfio_pci_reflck_alloc(void)
|
|
||||||
{
|
|
||||||
struct vfio_pci_reflck *reflck;
|
|
||||||
|
|
||||||
reflck = kzalloc(sizeof(*reflck), GFP_KERNEL);
|
|
||||||
if (!reflck)
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
|
|
||||||
kref_init(&reflck->kref);
|
|
||||||
mutex_init(&reflck->lock);
|
|
||||||
|
|
||||||
return reflck;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vfio_pci_reflck_get(struct vfio_pci_reflck *reflck)
|
|
||||||
{
|
|
||||||
kref_get(&reflck->kref);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int vfio_pci_reflck_find(struct pci_dev *pdev, void *data)
|
|
||||||
{
|
|
||||||
struct vfio_pci_reflck **preflck = data;
|
|
||||||
struct vfio_device *device;
|
|
||||||
struct vfio_pci_device *vdev;
|
|
||||||
|
|
||||||
device = vfio_device_get_from_dev(&pdev->dev);
|
|
||||||
if (!device)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (pci_dev_driver(pdev) != &vfio_pci_driver) {
|
|
||||||
vfio_device_put(device);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
vdev = container_of(device, struct vfio_pci_device, vdev);
|
|
||||||
|
|
||||||
if (vdev->reflck) {
|
|
||||||
vfio_pci_reflck_get(vdev->reflck);
|
|
||||||
*preflck = vdev->reflck;
|
|
||||||
vfio_device_put(device);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
vfio_device_put(device);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int vfio_pci_reflck_attach(struct vfio_pci_device *vdev)
|
|
||||||
{
|
|
||||||
bool slot = !pci_probe_reset_slot(vdev->pdev->slot);
|
|
||||||
|
|
||||||
mutex_lock(&reflck_lock);
|
|
||||||
|
|
||||||
if (pci_is_root_bus(vdev->pdev->bus) ||
|
|
||||||
vfio_pci_for_each_slot_or_bus(vdev->pdev, vfio_pci_reflck_find,
|
|
||||||
&vdev->reflck, slot) <= 0)
|
|
||||||
vdev->reflck = vfio_pci_reflck_alloc();
|
|
||||||
|
|
||||||
mutex_unlock(&reflck_lock);
|
|
||||||
|
|
||||||
return PTR_ERR_OR_ZERO(vdev->reflck);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vfio_pci_reflck_release(struct kref *kref)
|
|
||||||
{
|
|
||||||
struct vfio_pci_reflck *reflck = container_of(kref,
|
|
||||||
struct vfio_pci_reflck,
|
|
||||||
kref);
|
|
||||||
|
|
||||||
kfree(reflck);
|
|
||||||
mutex_unlock(&reflck_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vfio_pci_reflck_put(struct vfio_pci_reflck *reflck)
|
|
||||||
{
|
|
||||||
kref_put_mutex(&reflck->kref, vfio_pci_reflck_release, &reflck_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int vfio_pci_get_unused_devs(struct pci_dev *pdev, void *data)
|
static int vfio_pci_get_unused_devs(struct pci_dev *pdev, void *data)
|
||||||
{
|
{
|
||||||
struct vfio_devices *devs = data;
|
struct vfio_devices *devs = data;
|
||||||
@ -2254,7 +2166,7 @@ static int vfio_pci_get_unused_devs(struct pci_dev *pdev, void *data)
|
|||||||
vdev = container_of(device, struct vfio_pci_device, vdev);
|
vdev = container_of(device, struct vfio_pci_device, vdev);
|
||||||
|
|
||||||
/* Fault if the device is not unused */
|
/* Fault if the device is not unused */
|
||||||
if (vdev->refcnt) {
|
if (device->open_count) {
|
||||||
vfio_device_put(device);
|
vfio_device_put(device);
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
@ -2303,7 +2215,7 @@ static int vfio_pci_try_zap_and_vma_lock_cb(struct pci_dev *pdev, void *data)
|
|||||||
* - At least one of the affected devices is marked dirty via
|
* - At least one of the affected devices is marked dirty via
|
||||||
* needs_reset (such as by lack of FLR support)
|
* needs_reset (such as by lack of FLR support)
|
||||||
* Then attempt to perform that bus or slot reset. Callers are required
|
* Then attempt to perform that bus or slot reset. Callers are required
|
||||||
* to hold vdev->reflck->lock, protecting the bus/slot reset group from
|
* to hold vdev->dev_set->lock, protecting the bus/slot reset group from
|
||||||
* concurrent opens. A vfio_device reference is acquired for each device
|
* concurrent opens. A vfio_device reference is acquired for each device
|
||||||
* to prevent unbinds during the reset operation.
|
* to prevent unbinds during the reset operation.
|
||||||
*
|
*
|
||||||
|
@ -83,11 +83,6 @@ struct vfio_pci_dummy_resource {
|
|||||||
struct list_head res_next;
|
struct list_head res_next;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct vfio_pci_reflck {
|
|
||||||
struct kref kref;
|
|
||||||
struct mutex lock;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct vfio_pci_vf_token {
|
struct vfio_pci_vf_token {
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
uuid_t uuid;
|
uuid_t uuid;
|
||||||
@ -130,8 +125,6 @@ struct vfio_pci_device {
|
|||||||
bool needs_pm_restore;
|
bool needs_pm_restore;
|
||||||
struct pci_saved_state *pci_saved_state;
|
struct pci_saved_state *pci_saved_state;
|
||||||
struct pci_saved_state *pm_save;
|
struct pci_saved_state *pm_save;
|
||||||
struct vfio_pci_reflck *reflck;
|
|
||||||
int refcnt;
|
|
||||||
int ioeventfds_nr;
|
int ioeventfds_nr;
|
||||||
struct eventfd_ctx *err_trigger;
|
struct eventfd_ctx *err_trigger;
|
||||||
struct eventfd_ctx *req_trigger;
|
struct eventfd_ctx *req_trigger;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user