accel: Use XArray instead of IDR for minors

Accel minor management is based on DRM (and is also using struct
drm_minor internally), since DRM is using XArray for minors, it makes
sense to also convert accel.
As the two implementations are identical (only difference being the
underlying xarray), move the accel_minor_* functionality to DRM.

Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
Acked-by: James Zhu <James.Zhu@amd.com>
Acked-by: Christian König <christian.koenig@amd.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240823163048.2676257-3-michal.winiarski@intel.com
Signed-off-by: Christian König <christian.koenig@amd.com>
This commit is contained in:
Michał Winiarski 2024-08-23 18:30:47 +02:00 committed by Christian König
parent 5fbca8b48b
commit 45c4d994b8
6 changed files with 47 additions and 158 deletions

View File

@ -8,7 +8,7 @@
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/idr.h>
#include <linux/xarray.h>
#include <drm/drm_accel.h>
#include <drm/drm_auth.h>
@ -18,8 +18,7 @@
#include <drm/drm_ioctl.h>
#include <drm/drm_print.h>
static DEFINE_SPINLOCK(accel_minor_lock);
static struct idr accel_minors_idr;
DEFINE_XARRAY_ALLOC(accel_minors_xa);
static struct dentry *accel_debugfs_root;
@ -117,99 +116,6 @@ void accel_set_device_instance_params(struct device *kdev, int index)
kdev->type = &accel_sysfs_device_minor;
}
/**
* accel_minor_alloc() - Allocates a new accel minor
*
* This function access the accel minors idr and allocates from it
* a new id to represent a new accel minor
*
* Return: A new id on success or error code in case idr_alloc failed
*/
int accel_minor_alloc(void)
{
unsigned long flags;
int r;
spin_lock_irqsave(&accel_minor_lock, flags);
r = idr_alloc(&accel_minors_idr, NULL, 0, ACCEL_MAX_MINORS, GFP_NOWAIT);
spin_unlock_irqrestore(&accel_minor_lock, flags);
return r;
}
/**
* accel_minor_remove() - Remove an accel minor
* @index: The minor id to remove.
*
* This function access the accel minors idr and removes from
* it the member with the id that is passed to this function.
*/
void accel_minor_remove(int index)
{
unsigned long flags;
spin_lock_irqsave(&accel_minor_lock, flags);
idr_remove(&accel_minors_idr, index);
spin_unlock_irqrestore(&accel_minor_lock, flags);
}
/**
* accel_minor_replace() - Replace minor pointer in accel minors idr.
* @minor: Pointer to the new minor.
* @index: The minor id to replace.
*
* This function access the accel minors idr structure and replaces the pointer
* that is associated with an existing id. Because the minor pointer can be
* NULL, we need to explicitly pass the index.
*
* Return: 0 for success, negative value for error
*/
void accel_minor_replace(struct drm_minor *minor, int index)
{
unsigned long flags;
spin_lock_irqsave(&accel_minor_lock, flags);
idr_replace(&accel_minors_idr, minor, index);
spin_unlock_irqrestore(&accel_minor_lock, flags);
}
/*
* Looks up the given minor-ID and returns the respective DRM-minor object. The
* refence-count of the underlying device is increased so you must release this
* object with accel_minor_release().
*
* The object can be only a drm_minor that represents an accel device.
*
* As long as you hold this minor, it is guaranteed that the object and the
* minor->dev pointer will stay valid! However, the device may get unplugged and
* unregistered while you hold the minor.
*/
static struct drm_minor *accel_minor_acquire(unsigned int minor_id)
{
struct drm_minor *minor;
unsigned long flags;
spin_lock_irqsave(&accel_minor_lock, flags);
minor = idr_find(&accel_minors_idr, minor_id);
if (minor)
drm_dev_get(minor->dev);
spin_unlock_irqrestore(&accel_minor_lock, flags);
if (!minor) {
return ERR_PTR(-ENODEV);
} else if (drm_dev_is_unplugged(minor->dev)) {
drm_dev_put(minor->dev);
return ERR_PTR(-ENODEV);
}
return minor;
}
static void accel_minor_release(struct drm_minor *minor)
{
drm_dev_put(minor->dev);
}
/**
* accel_open - open method for ACCEL file
* @inode: device inode
@ -227,7 +133,7 @@ int accel_open(struct inode *inode, struct file *filp)
struct drm_minor *minor;
int retcode;
minor = accel_minor_acquire(iminor(inode));
minor = drm_minor_acquire(&accel_minors_xa, iminor(inode));
if (IS_ERR(minor))
return PTR_ERR(minor);
@ -246,7 +152,7 @@ int accel_open(struct inode *inode, struct file *filp)
err_undo:
atomic_dec(&dev->open_count);
accel_minor_release(minor);
drm_minor_release(minor);
return retcode;
}
EXPORT_SYMBOL_GPL(accel_open);
@ -257,7 +163,7 @@ static int accel_stub_open(struct inode *inode, struct file *filp)
struct drm_minor *minor;
int err;
minor = accel_minor_acquire(iminor(inode));
minor = drm_minor_acquire(&accel_minors_xa, iminor(inode));
if (IS_ERR(minor))
return PTR_ERR(minor);
@ -274,7 +180,7 @@ static int accel_stub_open(struct inode *inode, struct file *filp)
err = 0;
out:
accel_minor_release(minor);
drm_minor_release(minor);
return err;
}
@ -290,15 +196,13 @@ void accel_core_exit(void)
unregister_chrdev(ACCEL_MAJOR, "accel");
debugfs_remove(accel_debugfs_root);
accel_sysfs_destroy();
idr_destroy(&accel_minors_idr);
WARN_ON(!xa_empty(&accel_minors_xa));
}
int __init accel_core_init(void)
{
int ret;
idr_init(&accel_minors_idr);
ret = accel_sysfs_init();
if (ret < 0) {
DRM_ERROR("Cannot create ACCEL class: %d\n", ret);

View File

@ -55,7 +55,7 @@ MODULE_AUTHOR("Gareth Hughes, Leif Delgass, José Fonseca, Jon Smirl");
MODULE_DESCRIPTION("DRM shared core routines");
MODULE_LICENSE("GPL and additional rights");
static DEFINE_XARRAY_ALLOC(drm_minors_xa);
DEFINE_XARRAY_ALLOC(drm_minors_xa);
/*
* If the drm core fails to init for whatever reason,
@ -83,6 +83,18 @@ DEFINE_STATIC_SRCU(drm_unplug_srcu);
* registered and unregistered dynamically according to device-state.
*/
static struct xarray *drm_minor_get_xa(enum drm_minor_type type)
{
if (type == DRM_MINOR_PRIMARY || type == DRM_MINOR_RENDER)
return &drm_minors_xa;
#if IS_ENABLED(CONFIG_DRM_ACCEL)
else if (type == DRM_MINOR_ACCEL)
return &accel_minors_xa;
#endif
else
return ERR_PTR(-EOPNOTSUPP);
}
static struct drm_minor **drm_minor_get_slot(struct drm_device *dev,
enum drm_minor_type type)
{
@ -106,18 +118,18 @@ static void drm_minor_alloc_release(struct drm_device *dev, void *data)
put_device(minor->kdev);
if (minor->type == DRM_MINOR_ACCEL)
accel_minor_remove(minor->index);
else
xa_erase(&drm_minors_xa, minor->index);
xa_erase(drm_minor_get_xa(minor->type), minor->index);
}
#define DRM_MINOR_LIMIT(t) ({ typeof(t) _t = (t); XA_LIMIT(64 * _t, 64 * _t + 63); })
#define DRM_MINOR_LIMIT(t) ({ \
typeof(t) _t = (t); \
_t == DRM_MINOR_ACCEL ? XA_LIMIT(0, ACCEL_MAX_MINORS) : XA_LIMIT(64 * _t, 64 * _t + 63); \
})
static int drm_minor_alloc(struct drm_device *dev, enum drm_minor_type type)
{
struct drm_minor *minor;
int index, r;
int r;
minor = drmm_kzalloc(dev, sizeof(*minor), GFP_KERNEL);
if (!minor)
@ -126,18 +138,11 @@ static int drm_minor_alloc(struct drm_device *dev, enum drm_minor_type type)
minor->type = type;
minor->dev = dev;
if (type == DRM_MINOR_ACCEL) {
r = accel_minor_alloc();
index = r;
} else {
r = xa_alloc(&drm_minors_xa, &index, NULL, DRM_MINOR_LIMIT(type), GFP_KERNEL);
}
r = xa_alloc(drm_minor_get_xa(type), &minor->index,
NULL, DRM_MINOR_LIMIT(type), GFP_KERNEL);
if (r < 0)
return r;
minor->index = index;
r = drmm_add_action_or_reset(dev, drm_minor_alloc_release, minor);
if (r)
return r;
@ -176,16 +181,12 @@ static int drm_minor_register(struct drm_device *dev, enum drm_minor_type type)
goto err_debugfs;
/* replace NULL with @minor so lookups will succeed from now on */
if (minor->type == DRM_MINOR_ACCEL) {
accel_minor_replace(minor, minor->index);
} else {
entry = xa_store(&drm_minors_xa, minor->index, minor, GFP_KERNEL);
if (xa_is_err(entry)) {
ret = xa_err(entry);
goto err_debugfs;
}
WARN_ON(entry);
entry = xa_store(drm_minor_get_xa(type), minor->index, minor, GFP_KERNEL);
if (xa_is_err(entry)) {
ret = xa_err(entry);
goto err_debugfs;
}
WARN_ON(entry);
DRM_DEBUG("new minor registered %d\n", minor->index);
return 0;
@ -204,10 +205,7 @@ static void drm_minor_unregister(struct drm_device *dev, enum drm_minor_type typ
return;
/* replace @minor with NULL so lookups will fail from now on */
if (minor->type == DRM_MINOR_ACCEL)
accel_minor_replace(NULL, minor->index);
else
xa_store(&drm_minors_xa, minor->index, NULL, GFP_KERNEL);
xa_store(drm_minor_get_xa(type), minor->index, NULL, GFP_KERNEL);
device_del(minor->kdev);
dev_set_drvdata(minor->kdev, NULL); /* safety belt */
@ -223,15 +221,15 @@ static void drm_minor_unregister(struct drm_device *dev, enum drm_minor_type typ
* minor->dev pointer will stay valid! However, the device may get unplugged and
* unregistered while you hold the minor.
*/
struct drm_minor *drm_minor_acquire(unsigned int minor_id)
struct drm_minor *drm_minor_acquire(struct xarray *minor_xa, unsigned int minor_id)
{
struct drm_minor *minor;
xa_lock(&drm_minors_xa);
minor = xa_load(&drm_minors_xa, minor_id);
xa_lock(minor_xa);
minor = xa_load(minor_xa, minor_id);
if (minor)
drm_dev_get(minor->dev);
xa_unlock(&drm_minors_xa);
xa_unlock(minor_xa);
if (!minor) {
return ERR_PTR(-ENODEV);
@ -1024,7 +1022,7 @@ static int drm_stub_open(struct inode *inode, struct file *filp)
DRM_DEBUG("\n");
minor = drm_minor_acquire(iminor(inode));
minor = drm_minor_acquire(&drm_minors_xa, iminor(inode));
if (IS_ERR(minor))
return PTR_ERR(minor);

View File

@ -355,7 +355,7 @@ int drm_open(struct inode *inode, struct file *filp)
struct drm_minor *minor;
int retcode;
minor = drm_minor_acquire(iminor(inode));
minor = drm_minor_acquire(&drm_minors_xa, iminor(inode));
if (IS_ERR(minor))
return PTR_ERR(minor);

View File

@ -80,10 +80,6 @@ void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv);
void drm_prime_remove_buf_handle(struct drm_prime_file_private *prime_fpriv,
uint32_t handle);
/* drm_drv.c */
struct drm_minor *drm_minor_acquire(unsigned int minor_id);
void drm_minor_release(struct drm_minor *minor);
/* drm_managed.c */
void drm_managed_release(struct drm_device *dev);
void drmm_add_final_kfree(struct drm_device *dev, void *container);

View File

@ -51,11 +51,10 @@
#if IS_ENABLED(CONFIG_DRM_ACCEL)
extern struct xarray accel_minors_xa;
void accel_core_exit(void);
int accel_core_init(void);
void accel_minor_remove(int index);
int accel_minor_alloc(void);
void accel_minor_replace(struct drm_minor *minor, int index);
void accel_set_device_instance_params(struct device *kdev, int index);
int accel_open(struct inode *inode, struct file *filp);
void accel_debugfs_init(struct drm_device *dev);
@ -73,19 +72,6 @@ static inline int __init accel_core_init(void)
return 0;
}
static inline void accel_minor_remove(int index)
{
}
static inline int accel_minor_alloc(void)
{
return -EOPNOTSUPP;
}
static inline void accel_minor_replace(struct drm_minor *minor, int index)
{
}
static inline void accel_set_device_instance_params(struct device *kdev, int index)
{
}

View File

@ -45,6 +45,8 @@ struct drm_printer;
struct device;
struct file;
extern struct xarray drm_minors_xa;
/*
* FIXME: Not sure we want to have drm_minor here in the end, but to avoid
* header include loops we need it here for now.
@ -434,6 +436,9 @@ static inline bool drm_is_accel_client(const struct drm_file *file_priv)
void drm_file_update_pid(struct drm_file *);
struct drm_minor *drm_minor_acquire(struct xarray *minors_xa, unsigned int minor_id);
void drm_minor_release(struct drm_minor *minor);
int drm_open(struct inode *inode, struct file *filp);
int drm_open_helper(struct file *filp, struct drm_minor *minor);
ssize_t drm_read(struct file *filp, char __user *buffer,