Skip to content

Commit

Permalink
vfio/mdev: embedd struct mdev_parent in the parent data structure
Browse files Browse the repository at this point in the history
Simplify mdev_{un}register_device by requiring the caller to pass in
a structure allocate as part of the parent device structure.  This
removes the need for a list of parents and the separate mdev_parent
refcount as we can simplify rely on the reference to the parent device.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Tony Krowiak <akrowiak@linux.ibm.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Kirti Wankhede <kwankhede@nvidia.com>
Reviewed-by: Eric Farman <farman@linux.ibm.com>
Link: https://lore.kernel.org/r/20220923092652.100656-5-hch@lst.de
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
  • Loading branch information
Christoph Hellwig authored and awilliam committed Oct 4, 2022
1 parent bdef2b7 commit 89345d5
Show file tree
Hide file tree
Showing 17 changed files with 71 additions and 146 deletions.
12 changes: 6 additions & 6 deletions Documentation/driver-api/vfio-mediated-device.rst
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,19 @@ devices as examples, as these devices are the first devices to use this module::
| MDEV CORE |
| MODULE |
| mdev.ko |
| +-----------+ | mdev_register_device() +--------------+
| +-----------+ | mdev_register_parent() +--------------+
| | | +<------------------------+ |
| | | | | nvidia.ko |<-> physical
| | | +------------------------>+ | device
| | | | callbacks +--------------+
| | Physical | |
| | device | | mdev_register_device() +--------------+
| | device | | mdev_register_parent() +--------------+
| | interface | |<------------------------+ |
| | | | | i915.ko |<-> physical
| | | +------------------------>+ | device
| | | | callbacks +--------------+
| | | |
| | | | mdev_register_device() +--------------+
| | | | mdev_register_parent() +--------------+
| | | +<------------------------+ |
| | | | | ccw_device.ko|<-> physical
| | | +------------------------>+ | device
Expand Down Expand Up @@ -125,16 +125,16 @@ vfio_device_ops.
When a driver wants to add the GUID creation sysfs to an existing device it has
probe'd to then it should call::

int mdev_register_device(struct device *dev,
struct mdev_driver *mdev_driver);
int mdev_register_parent(struct mdev_parent *parent, struct device *dev,
struct mdev_driver *mdev_driver);

This will provide the 'mdev_supported_types/XX/create' files which can then be
used to trigger the creation of a mdev_device. The created mdev_device will be
attached to the specified driver.

When the driver needs to remove itself it calls::

void mdev_unregister_device(struct device *dev);
void mdev_unregister_parent(struct mdev_parent *parent);

Which will unbind and destroy all the created mdevs and remove the sysfs files.

Expand Down
2 changes: 1 addition & 1 deletion Documentation/s390/vfio-ap.rst
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ of the VFIO AP mediated device driver::
| MDEV CORE |
| MODULE |
| mdev.ko |
| +---------+ | mdev_register_device() +--------------+
| +---------+ | mdev_register_parent() +--------------+
| |Physical | +<-----------------------+ |
| | device | | | vfio_ap.ko |<-> matrix
| |interface| +----------------------->+ | device
Expand Down
2 changes: 1 addition & 1 deletion Documentation/s390/vfio-ccw.rst
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ Below is a high Level block diagram::
| MDEV CORE |
| MODULE |
| mdev.ko |
| +---------+ | mdev_register_device() +--------------+
| +---------+ | mdev_register_parent() +--------------+
| |Physical | +<-----------------------+ |
| | device | | | vfio_ccw.ko |<-> subchannel
| |interface| +----------------------->+ | device
Expand Down
2 changes: 2 additions & 0 deletions drivers/gpu/drm/i915/gvt/gvt.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <uapi/linux/pci_regs.h>
#include <linux/kvm_host.h>
#include <linux/vfio.h>
#include <linux/mdev.h>

#include "i915_drv.h"
#include "intel_gvt.h"
Expand Down Expand Up @@ -337,6 +338,7 @@ struct intel_gvt {
struct intel_gvt_workload_scheduler scheduler;
struct notifier_block shadow_ctx_notifier_block[I915_NUM_ENGINES];
DECLARE_HASHTABLE(cmd_table, GVT_CMD_HASH_BITS);
struct mdev_parent parent;
struct intel_vgpu_type *types;
unsigned int num_types;
struct intel_vgpu *idle_vgpu;
Expand Down
5 changes: 3 additions & 2 deletions drivers/gpu/drm/i915/gvt/kvmgt.c
Original file line number Diff line number Diff line change
Expand Up @@ -1923,7 +1923,7 @@ static void intel_gvt_clean_device(struct drm_i915_private *i915)
if (drm_WARN_ON(&i915->drm, !gvt))
return;

mdev_unregister_device(i915->drm.dev);
mdev_unregister_parent(&gvt->parent);
intel_gvt_cleanup_vgpu_type_groups(gvt);
intel_gvt_destroy_idle_vgpu(gvt->idle_vgpu);
intel_gvt_clean_vgpu_types(gvt);
Expand Down Expand Up @@ -2028,7 +2028,8 @@ static int intel_gvt_init_device(struct drm_i915_private *i915)
if (ret)
goto out_destroy_idle_vgpu;

ret = mdev_register_device(i915->drm.dev, &intel_vgpu_mdev_driver);
ret = mdev_register_parent(&gvt->parent, i915->drm.dev,
&intel_vgpu_mdev_driver);
if (ret)
goto out_cleanup_vgpu_type_groups;

Expand Down
5 changes: 3 additions & 2 deletions drivers/s390/cio/vfio_ccw_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,8 @@ static int vfio_ccw_sch_probe(struct subchannel *sch)

dev_set_drvdata(&sch->dev, private);

ret = mdev_register_device(&sch->dev, &vfio_ccw_mdev_driver);
ret = mdev_register_parent(&private->parent, &sch->dev,
&vfio_ccw_mdev_driver);
if (ret)
goto out_free;

Expand All @@ -240,7 +241,7 @@ static void vfio_ccw_sch_remove(struct subchannel *sch)
{
struct vfio_ccw_private *private = dev_get_drvdata(&sch->dev);

mdev_unregister_device(&sch->dev);
mdev_unregister_parent(&private->parent);

dev_set_drvdata(&sch->dev, NULL);

Expand Down
1 change: 0 additions & 1 deletion drivers/s390/cio/vfio_ccw_ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
*/

#include <linux/vfio.h>
#include <linux/mdev.h>
#include <linux/nospec.h>
#include <linux/slab.h>

Expand Down
4 changes: 4 additions & 0 deletions drivers/s390/cio/vfio_ccw_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <linux/workqueue.h>
#include <linux/vfio_ccw.h>
#include <linux/vfio.h>
#include <linux/mdev.h>
#include <asm/crw.h>
#include <asm/debug.h>

Expand Down Expand Up @@ -89,6 +90,7 @@ struct vfio_ccw_crw {
* @io_work: work for deferral process of I/O handling
* @crw_work: work for deferral process of CRW handling
* @release_comp: synchronization helper for vfio device release
* @parent: parent data structures for mdevs created
*/
struct vfio_ccw_private {
struct vfio_device vdev;
Expand Down Expand Up @@ -116,6 +118,8 @@ struct vfio_ccw_private {
struct work_struct crw_work;

struct completion release_comp;

struct mdev_parent parent;
} __aligned(8);

int vfio_ccw_sch_quiesce(struct subchannel *sch);
Expand Down
5 changes: 3 additions & 2 deletions drivers/s390/crypto/vfio_ap_ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -1830,7 +1830,8 @@ int vfio_ap_mdev_register(void)
if (ret)
return ret;

ret = mdev_register_device(&matrix_dev->device, &vfio_ap_matrix_driver);
ret = mdev_register_parent(&matrix_dev->parent, &matrix_dev->device,
&vfio_ap_matrix_driver);
if (ret)
goto err_driver;
return 0;
Expand All @@ -1842,7 +1843,7 @@ int vfio_ap_mdev_register(void)

void vfio_ap_mdev_unregister(void)
{
mdev_unregister_device(&matrix_dev->device);
mdev_unregister_parent(&matrix_dev->parent);
mdev_unregister_driver(&vfio_ap_matrix_driver);
}

Expand Down
1 change: 1 addition & 0 deletions drivers/s390/crypto/vfio_ap_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ struct ap_matrix_dev {
struct mutex mdevs_lock; /* serializes access to each ap_matrix_mdev */
struct ap_driver *vfio_ap_drv;
struct mutex guests_lock; /* serializes access to each KVM guest */
struct mdev_parent parent;
};

extern struct ap_matrix_dev *matrix_dev;
Expand Down
120 changes: 22 additions & 98 deletions drivers/vfio/mdev/mdev_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
#define DRIVER_AUTHOR "NVIDIA Corporation"
#define DRIVER_DESC "Mediated device Core Driver"

static LIST_HEAD(parent_list);
static DEFINE_MUTEX(parent_list_lock);
static struct class_compat *mdev_bus_compat_class;

static LIST_HEAD(mdev_list);
Expand Down Expand Up @@ -61,28 +59,6 @@ struct device *mtype_get_parent_dev(struct mdev_type *mtype)
}
EXPORT_SYMBOL(mtype_get_parent_dev);

/* Should be called holding parent_list_lock */
static struct mdev_parent *__find_parent_device(struct device *dev)
{
struct mdev_parent *parent;

list_for_each_entry(parent, &parent_list, next) {
if (parent->dev == dev)
return parent;
}
return NULL;
}

void mdev_release_parent(struct kref *kref)
{
struct mdev_parent *parent = container_of(kref, struct mdev_parent,
ref);
struct device *dev = parent->dev;

kfree(parent);
put_device(dev);
}

/* Caller must hold parent unreg_sem read or write lock */
static void mdev_device_remove_common(struct mdev_device *mdev)
{
Expand All @@ -105,125 +81,73 @@ static int mdev_device_remove_cb(struct device *dev, void *data)
}

/*
* mdev_register_device : Register a device
* mdev_register_parent: Register a device as parent for mdevs
* @parent: parent structure registered
* @dev: device structure representing parent device.
* @mdev_driver: Device driver to bind to the newly created mdev
*
* Add device to list of registered parent devices.
* Registers the @parent stucture as a parent for mdev types and thus mdev
* devices. The caller needs to hold a reference on @dev that must not be
* released until after the call to mdev_unregister_parent().
*
* Returns a negative value on error, otherwise 0.
*/
int mdev_register_device(struct device *dev, struct mdev_driver *mdev_driver)
int mdev_register_parent(struct mdev_parent *parent, struct device *dev,
struct mdev_driver *mdev_driver)
{
int ret;
struct mdev_parent *parent;
char *env_string = "MDEV_STATE=registered";
char *envp[] = { env_string, NULL };
int ret;

/* check for mandatory ops */
if (!mdev_driver->supported_type_groups)
return -EINVAL;

dev = get_device(dev);
if (!dev)
return -EINVAL;

mutex_lock(&parent_list_lock);

/* Check for duplicate */
parent = __find_parent_device(dev);
if (parent) {
parent = NULL;
ret = -EEXIST;
goto add_dev_err;
}

parent = kzalloc(sizeof(*parent), GFP_KERNEL);
if (!parent) {
ret = -ENOMEM;
goto add_dev_err;
}

kref_init(&parent->ref);
memset(parent, 0, sizeof(*parent));
init_rwsem(&parent->unreg_sem);

parent->dev = dev;
parent->mdev_driver = mdev_driver;

if (!mdev_bus_compat_class) {
mdev_bus_compat_class = class_compat_register("mdev_bus");
if (!mdev_bus_compat_class) {
ret = -ENOMEM;
goto add_dev_err;
}
if (!mdev_bus_compat_class)
return -ENOMEM;
}

ret = parent_create_sysfs_files(parent);
if (ret)
goto add_dev_err;
return ret;

ret = class_compat_create_link(mdev_bus_compat_class, dev, NULL);
if (ret)
dev_warn(dev, "Failed to create compatibility class link\n");

list_add(&parent->next, &parent_list);
mutex_unlock(&parent_list_lock);

dev_info(dev, "MDEV: Registered\n");
kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);

return 0;

add_dev_err:
mutex_unlock(&parent_list_lock);
if (parent)
mdev_put_parent(parent);
else
put_device(dev);
return ret;
}
EXPORT_SYMBOL(mdev_register_device);
EXPORT_SYMBOL(mdev_register_parent);

/*
* mdev_unregister_device : Unregister a parent device
* @dev: device structure representing parent device.
*
* Remove device from list of registered parent devices. Give a chance to free
* existing mediated devices for given device.
* mdev_unregister_parent : Unregister a parent device
* @parent: parent structure to unregister
*/

void mdev_unregister_device(struct device *dev)
void mdev_unregister_parent(struct mdev_parent *parent)
{
struct mdev_parent *parent;
char *env_string = "MDEV_STATE=unregistered";
char *envp[] = { env_string, NULL };

mutex_lock(&parent_list_lock);
parent = __find_parent_device(dev);

if (!parent) {
mutex_unlock(&parent_list_lock);
return;
}
dev_info(dev, "MDEV: Unregistering\n");

list_del(&parent->next);
mutex_unlock(&parent_list_lock);
dev_info(parent->dev, "MDEV: Unregistering\n");

down_write(&parent->unreg_sem);

class_compat_remove_link(mdev_bus_compat_class, dev, NULL);

device_for_each_child(dev, NULL, mdev_device_remove_cb);

class_compat_remove_link(mdev_bus_compat_class, parent->dev, NULL);
device_for_each_child(parent->dev, NULL, mdev_device_remove_cb);
parent_remove_sysfs_files(parent);
up_write(&parent->unreg_sem);

mdev_put_parent(parent);

/* We still have the caller's reference to use for the uevent */
kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
kobject_uevent_env(&parent->dev->kobj, KOBJ_CHANGE, envp);
}
EXPORT_SYMBOL(mdev_unregister_device);
EXPORT_SYMBOL(mdev_unregister_parent);

static void mdev_device_release(struct device *dev)
{
Expand Down
23 changes: 0 additions & 23 deletions drivers/vfio/mdev/mdev_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,6 @@
int mdev_bus_register(void);
void mdev_bus_unregister(void);

struct mdev_parent {
struct device *dev;
struct mdev_driver *mdev_driver;
struct kref ref;
struct list_head next;
struct kset *mdev_types_kset;
struct list_head type_list;
/* Synchronize device creation/removal with parent unregistration */
struct rw_semaphore unreg_sem;
};

struct mdev_type {
struct kobject kobj;
struct kobject *devices_kobj;
Expand All @@ -48,16 +37,4 @@ void mdev_remove_sysfs_files(struct mdev_device *mdev);
int mdev_device_create(struct mdev_type *kobj, const guid_t *uuid);
int mdev_device_remove(struct mdev_device *dev);

void mdev_release_parent(struct kref *kref);

static inline void mdev_get_parent(struct mdev_parent *parent)
{
kref_get(&parent->ref);
}

static inline void mdev_put_parent(struct mdev_parent *parent)
{
kref_put(&parent->ref, mdev_release_parent);
}

#endif /* MDEV_PRIVATE_H */
Loading

0 comments on commit 89345d5

Please sign in to comment.