Commit 795bd9bb authored by Dave Airlie's avatar Dave Airlie

Merge tag 'drm-accel-2022-11-22' of...

Merge tag 'drm-accel-2022-11-22' of https://git.kernel.org/pub/scm/linux/kernel/git/ogabbay/accel into drm-next

This tag contains the patches that add the new compute acceleration
subsystem, which is part of the DRM subsystem.

The patches:
- Add a new directory at drivers/accel.
- Add a new major (261) for compute accelerators.
- Add a new DRM minor type for compute accelerators.
- Integrate the accel core code with DRM core code.
- Add documentation for the accel subsystem.
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

some acks from the list (some are in the patch series):
Acked-by: default avatarDaniel Stone <daniels@collabora.com>
Acked-by: default avatarSonal Santan <sonal.santan@amd.com>
Acked-by: default avatarMaxime Ripard <maxime@cerno.tech>
Acked-by: default avatarJacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com>
Tested-by: default avatarJacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com>
Acked-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Acked-by: default avatarThomas Zimmermann <tzimmermann@suse.de>

From: Oded Gabbay <ogabbay@kernel.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20221122112222.GA352082@ogabbay-vm-u20.habana-labs.com
parents 2847b668 8c5577a5
.. SPDX-License-Identifier: GPL-2.0
====================
Compute Accelerators
====================
.. toctree::
:maxdepth: 1
introduction
.. only:: subproject and html
Indices
=======
* :ref:`genindex`
.. SPDX-License-Identifier: GPL-2.0
============
Introduction
============
The Linux compute accelerators subsystem is designed to expose compute
accelerators in a common way to user-space and provide a common set of
functionality.
These devices can be either stand-alone ASICs or IP blocks inside an SoC/GPU.
Although these devices are typically designed to accelerate
Machine-Learning (ML) and/or Deep-Learning (DL) computations, the accel layer
is not limited to handling these types of accelerators.
Typically, a compute accelerator will belong to one of the following
categories:
- Edge AI - doing inference at an edge device. It can be an embedded ASIC/FPGA,
or an IP inside a SoC (e.g. laptop web camera). These devices
are typically configured using registers and can work with or without DMA.
- Inference data-center - single/multi user devices in a large server. This
type of device can be stand-alone or an IP inside a SoC or a GPU. It will
have on-board DRAM (to hold the DL topology), DMA engines and
command submission queues (either kernel or user-space queues).
It might also have an MMU to manage multiple users and might also enable
virtualization (SR-IOV) to support multiple VMs on the same device. In
addition, these devices will usually have some tools, such as profiler and
debugger.
- Training data-center - Similar to Inference data-center cards, but typically
have more computational power and memory b/w (e.g. HBM) and will likely have
a method of scaling-up/out, i.e. connecting to other training cards inside
the server or in other servers, respectively.
All these devices typically have different runtime user-space software stacks,
that are tailored-made to their h/w. In addition, they will also probably
include a compiler to generate programs to their custom-made computational
engines. Typically, the common layer in user-space will be the DL frameworks,
such as PyTorch and TensorFlow.
Sharing code with DRM
=====================
Because this type of devices can be an IP inside GPUs or have similar
characteristics as those of GPUs, the accel subsystem will use the
DRM subsystem's code and functionality. i.e. the accel core code will
be part of the DRM subsystem and an accel device will be a new type of DRM
device.
This will allow us to leverage the extensive DRM code-base and
collaborate with DRM developers that have experience with this type of
devices. In addition, new features that will be added for the accelerator
drivers can be of use to GPU drivers as well.
Differentiation from GPUs
=========================
Because we want to prevent the extensive user-space graphic software stack
from trying to use an accelerator as a GPU, the compute accelerators will be
differentiated from GPUs by using a new major number and new device char files.
Furthermore, the drivers will be located in a separate place in the kernel
tree - drivers/accel/.
The accelerator devices will be exposed to the user space with the dedicated
261 major number and will have the following convention:
- device char files - /dev/accel/accel*
- sysfs - /sys/class/accel/accel*/
- debugfs - /sys/kernel/debug/accel/accel*/
Getting Started
===============
First, read the DRM documentation at Documentation/gpu/index.rst.
Not only it will explain how to write a new DRM driver but it will also
contain all the information on how to contribute, the Code Of Conduct and
what is the coding style/documentation. All of that is the same for the
accel subsystem.
Second, make sure the kernel is configured with CONFIG_DRM_ACCEL.
To expose your device as an accelerator, two changes are needed to
be done in your driver (as opposed to a standard DRM driver):
- Add the DRIVER_COMPUTE_ACCEL feature flag in your drm_driver's
driver_features field. It is important to note that this driver feature is
mutually exclusive with DRIVER_RENDER and DRIVER_MODESET. Devices that want
to expose both graphics and compute device char files should be handled by
two drivers that are connected using the auxiliary bus framework.
- Change the open callback in your driver fops structure to accel_open().
Alternatively, your driver can use DEFINE_DRM_ACCEL_FOPS macro to easily
set the correct function operations pointers structure.
External References
===================
email threads
-------------
* `Initial discussion on the New subsystem for acceleration devices <https://lkml.org/lkml/2022/7/31/83>`_ - Oded Gabbay (2022)
* `patch-set to add the new subsystem <https://lkml.org/lkml/2022/10/22/544>`_ - Oded Gabbay (2022)
Conference talks
----------------
* `LPC 2022 Accelerators BOF outcomes summary <https://airlied.blogspot.com/2022/09/accelerators-bof-outcomes-summary.html>`_ - Dave Airlie (2022)
......@@ -3080,6 +3080,11 @@
...
255 = /dev/osd255 256th OSD Device
261 char Compute Acceleration Devices
0 = /dev/accel/accel0 First acceleration device
1 = /dev/accel/accel1 Second acceleration device
...
384-511 char RESERVED FOR DYNAMIC ASSIGNMENT
Character devices that request a dynamic allocation of major
number will take numbers starting from 511 and downward,
......
......@@ -43,6 +43,7 @@ needed).
input/index
hwmon/index
gpu/index
accel/index
security/index
sound/index
crypto/index
......
......@@ -6836,6 +6836,15 @@ F: include/drm/drm*
F: include/linux/vga*
F: include/uapi/drm/drm*
DRM COMPUTE ACCELERATORS DRIVERS AND FRAMEWORK
M: Oded Gabbay <ogabbay@kernel.org>
L: dri-devel@lists.freedesktop.org
S: Maintained
C: irc://irc.oftc.net/dri-devel
T: git https://git.kernel.org/pub/scm/linux/kernel/git/ogabbay/accel.git
F: Documentation/accel/
F: drivers/accel/
DRM DRIVERS FOR ALLWINNER A10
M: Maxime Ripard <mripard@kernel.org>
M: Chen-Yu Tsai <wens@csie.org>
......
......@@ -99,6 +99,8 @@ source "drivers/media/Kconfig"
source "drivers/video/Kconfig"
source "drivers/accel/Kconfig"
source "sound/Kconfig"
source "drivers/hid/Kconfig"
......
# SPDX-License-Identifier: GPL-2.0-only
#
# Compute Acceleration device configuration
#
# This framework provides support for compute acceleration devices, such
# as, but not limited to, Machine-Learning and Deep-Learning acceleration
# devices
#
menuconfig DRM_ACCEL
bool "Compute Acceleration Framework"
depends on DRM
help
Framework for device drivers of compute acceleration devices, such
as, but not limited to, Machine-Learning and Deep-Learning
acceleration devices.
If you say Y here, you need to select the module that's right for
your acceleration device from the list below.
This framework is integrated with the DRM subsystem as compute
accelerators and GPUs share a lot in common and can use almost the
same infrastructure code.
Having said that, acceleration devices will have a different
major number than GPUs, and will be exposed to user-space using
different device files, called accel/accel* (in /dev, sysfs
and debugfs).
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2022 HabanaLabs, Ltd.
* All Rights Reserved.
*
*/
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/idr.h>
#include <drm/drm_accel.h>
#include <drm/drm_debugfs.h>
#include <drm/drm_drv.h>
#include <drm/drm_file.h>
#include <drm/drm_ioctl.h>
#include <drm/drm_print.h>
static DEFINE_SPINLOCK(accel_minor_lock);
static struct idr accel_minors_idr;
static struct dentry *accel_debugfs_root;
static struct class *accel_class;
static struct device_type accel_sysfs_device_minor = {
.name = "accel_minor"
};
static char *accel_devnode(struct device *dev, umode_t *mode)
{
return kasprintf(GFP_KERNEL, "accel/%s", dev_name(dev));
}
static int accel_sysfs_init(void)
{
accel_class = class_create(THIS_MODULE, "accel");
if (IS_ERR(accel_class))
return PTR_ERR(accel_class);
accel_class->devnode = accel_devnode;
return 0;
}
static void accel_sysfs_destroy(void)
{
if (IS_ERR_OR_NULL(accel_class))
return;
class_destroy(accel_class);
accel_class = NULL;
}
static int accel_name_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_minor *minor = node->minor;
struct drm_device *dev = minor->dev;
struct drm_master *master;
mutex_lock(&dev->master_mutex);
master = dev->master;
seq_printf(m, "%s", dev->driver->name);
if (dev->dev)
seq_printf(m, " dev=%s", dev_name(dev->dev));
if (master && master->unique)
seq_printf(m, " master=%s", master->unique);
if (dev->unique)
seq_printf(m, " unique=%s", dev->unique);
seq_puts(m, "\n");
mutex_unlock(&dev->master_mutex);
return 0;
}
static const struct drm_info_list accel_debugfs_list[] = {
{"name", accel_name_info, 0}
};
#define ACCEL_DEBUGFS_ENTRIES ARRAY_SIZE(accel_debugfs_list)
/**
* accel_debugfs_init() - Initialize debugfs for accel minor
* @minor: Pointer to the drm_minor instance.
* @minor_id: The minor's id
*
* This function initializes the drm minor's debugfs members and creates
* a root directory for the minor in debugfs. It also creates common files
* for accelerators and calls the driver's debugfs init callback.
*/
void accel_debugfs_init(struct drm_minor *minor, int minor_id)
{
struct drm_device *dev = minor->dev;
char name[64];
INIT_LIST_HEAD(&minor->debugfs_list);
mutex_init(&minor->debugfs_lock);
sprintf(name, "%d", minor_id);
minor->debugfs_root = debugfs_create_dir(name, accel_debugfs_root);
drm_debugfs_create_files(accel_debugfs_list, ACCEL_DEBUGFS_ENTRIES,
minor->debugfs_root, minor);
if (dev->driver->debugfs_init)
dev->driver->debugfs_init(minor);
}
/**
* accel_set_device_instance_params() - Set some device parameters for accel device
* @kdev: Pointer to the device instance.
* @index: The minor's index
*
* This function creates the dev_t of the device using the accel major and
* the device's minor number. In addition, it sets the class and type of the
* device instance to the accel sysfs class and device type, respectively.
*/
void accel_set_device_instance_params(struct device *kdev, int index)
{
kdev->devt = MKDEV(ACCEL_MAJOR, index);
kdev->class = accel_class;
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
* @filp: file pointer.
*
* This function must be used by drivers as their &file_operations.open method.
* It looks up the correct ACCEL device and instantiates all the per-file
* resources for it. It also calls the &drm_driver.open driver callback.
*
* Return: 0 on success or negative errno value on failure.
*/
int accel_open(struct inode *inode, struct file *filp)
{
struct drm_device *dev;
struct drm_minor *minor;
int retcode;
minor = accel_minor_acquire(iminor(inode));
if (IS_ERR(minor))
return PTR_ERR(minor);
dev = minor->dev;
atomic_fetch_inc(&dev->open_count);
/* share address_space across all char-devs of a single device */
filp->f_mapping = dev->anon_inode->i_mapping;
retcode = drm_open_helper(filp, minor);
if (retcode)
goto err_undo;
return 0;
err_undo:
atomic_dec(&dev->open_count);
accel_minor_release(minor);
return retcode;
}
EXPORT_SYMBOL_GPL(accel_open);
static int accel_stub_open(struct inode *inode, struct file *filp)
{
const struct file_operations *new_fops;
struct drm_minor *minor;
int err;
minor = accel_minor_acquire(iminor(inode));
if (IS_ERR(minor))
return PTR_ERR(minor);
new_fops = fops_get(minor->dev->driver->fops);
if (!new_fops) {
err = -ENODEV;
goto out;
}
replace_fops(filp, new_fops);
if (filp->f_op->open)
err = filp->f_op->open(inode, filp);
else
err = 0;
out:
accel_minor_release(minor);
return err;
}
static const struct file_operations accel_stub_fops = {
.owner = THIS_MODULE,
.open = accel_stub_open,
.llseek = noop_llseek,
};
void accel_core_exit(void)
{
unregister_chrdev(ACCEL_MAJOR, "accel");
debugfs_remove(accel_debugfs_root);
accel_sysfs_destroy();
idr_destroy(&accel_minors_idr);
}
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);
goto error;
}
accel_debugfs_root = debugfs_create_dir("accel", NULL);
ret = register_chrdev(ACCEL_MAJOR, "accel", &accel_stub_fops);
if (ret < 0)
DRM_ERROR("Cannot register ACCEL major: %d\n", ret);
error:
/*
* Any cleanup due to errors will be done in drm_core_exit() that
* will call accel_core_exit()
*/
return ret;
}
......@@ -70,6 +70,7 @@ drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
drm-$(CONFIG_DRM_PRIVACY_SCREEN) += \
drm_privacy_screen.o \
drm_privacy_screen_x86.o
drm-$(CONFIG_DRM_ACCEL) += ../../accel/drm_accel.o
obj-$(CONFIG_DRM) += drm.o
obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o
......
......@@ -35,6 +35,7 @@
#include <linux/slab.h>
#include <linux/srcu.h>
#include <drm/drm_accel.h>
#include <drm/drm_cache.h>
#include <drm/drm_client.h>
#include <drm/drm_color_mgmt.h>
......@@ -90,6 +91,8 @@ static struct drm_minor **drm_minor_get_slot(struct drm_device *dev,
return &dev->primary;
case DRM_MINOR_RENDER:
return &dev->render;
case DRM_MINOR_ACCEL:
return &dev->accel;
default:
BUG();
}
......@@ -104,9 +107,13 @@ static void drm_minor_alloc_release(struct drm_device *dev, void *data)
put_device(minor->kdev);
spin_lock_irqsave(&drm_minor_lock, flags);
idr_remove(&drm_minors_idr, minor->index);
spin_unlock_irqrestore(&drm_minor_lock, flags);
if (minor->type == DRM_MINOR_ACCEL) {
accel_minor_remove(minor->index);
} else {
spin_lock_irqsave(&drm_minor_lock, flags);
idr_remove(&drm_minors_idr, minor->index);
spin_unlock_irqrestore(&drm_minor_lock, flags);
}
}
static int drm_minor_alloc(struct drm_device *dev, unsigned int type)
......@@ -123,13 +130,17 @@ static int drm_minor_alloc(struct drm_device *dev, unsigned int type)
minor->dev = dev;
idr_preload(GFP_KERNEL);
spin_lock_irqsave(&drm_minor_lock, flags);
r = idr_alloc(&drm_minors_idr,
NULL,
64 * type,
64 * (type + 1),
GFP_NOWAIT);
spin_unlock_irqrestore(&drm_minor_lock, flags);
if (type == DRM_MINOR_ACCEL) {
r = accel_minor_alloc();
} else {
spin_lock_irqsave(&drm_minor_lock, flags);
r = idr_alloc(&drm_minors_idr,
NULL,
64 * type,
64 * (type + 1),
GFP_NOWAIT);
spin_unlock_irqrestore(&drm_minor_lock, flags);
}
idr_preload_end();
if (r < 0)
......@@ -161,10 +172,14 @@ static int drm_minor_register(struct drm_device *dev, unsigned int type)
if (!minor)
return 0;
ret = drm_debugfs_init(minor, minor->index, drm_debugfs_root);
if (ret) {
DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n");
goto err_debugfs;
if (minor->type == DRM_MINOR_ACCEL) {
accel_debugfs_init(minor, minor->index);
} else {
ret = drm_debugfs_init(minor, minor->index, drm_debugfs_root);
if (ret) {
DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n");
goto err_debugfs;
}
}
ret = device_add(minor->kdev);
......@@ -172,9 +187,13 @@ static int drm_minor_register(struct drm_device *dev, unsigned int type)
goto err_debugfs;
/* replace NULL with @minor so lookups will succeed from now on */
spin_lock_irqsave(&drm_minor_lock, flags);
idr_replace(&drm_minors_idr, minor, minor->index);
spin_unlock_irqrestore(&drm_minor_lock, flags);
if (minor->type == DRM_MINOR_ACCEL) {
accel_minor_replace(minor, minor->index);
} else {
spin_lock_irqsave(&drm_minor_lock, flags);
idr_replace(&drm_minors_idr, minor, minor->index);
spin_unlock_irqrestore(&drm_minor_lock, flags);
}
DRM_DEBUG("new minor registered %d\n", minor->index);
return 0;
......@@ -194,9 +213,13 @@ static void drm_minor_unregister(struct drm_device *dev, unsigned int type)
return;
/* replace @minor with NULL so lookups will fail from now on */
spin_lock_irqsave(&drm_minor_lock, flags);
idr_replace(&drm_minors_idr, NULL, minor->index);
spin_unlock_irqrestore(&drm_minor_lock, flags);
if (minor->type == DRM_MINOR_ACCEL) {
accel_minor_replace(NULL, minor->index);
} else {
spin_lock_irqsave(&drm_minor_lock, flags);
idr_replace(&drm_minors_idr, NULL, minor->index);
spin_unlock_irqrestore(&drm_minor_lock, flags);
}
device_del(minor->kdev);
dev_set_drvdata(minor->kdev, NULL); /* safety belt */
......@@ -603,6 +626,13 @@ static int drm_dev_init(struct drm_device *dev,
/* no per-device feature limits by default */
dev->driver_features = ~0u;
if (drm_core_check_feature(dev, DRIVER_COMPUTE_ACCEL) &&
(drm_core_check_feature(dev, DRIVER_RENDER) ||
drm_core_check_feature(dev, DRIVER_MODESET))) {
DRM_ERROR("DRM driver can't be both a compute acceleration and graphics driver\n");
return -EINVAL;
}
drm_legacy_init_members(dev);
INIT_LIST_HEAD(&dev->filelist);
INIT_LIST_HEAD(&dev->filelist_internal);
......@@ -628,15 +658,21 @@ static int drm_dev_init(struct drm_device *dev,
dev->anon_inode = inode;
if (drm_core_check_feature(dev, DRIVER_RENDER)) {
ret = drm_minor_alloc(dev, DRM_MINOR_RENDER);
if (drm_core_check_feature(dev, DRIVER_COMPUTE_ACCEL)) {
ret = drm_minor_alloc(dev, DRM_MINOR_ACCEL);
if (ret)
goto err;
}
} else {
if (drm_core_check_feature(dev, DRIVER_RENDER)) {
ret = drm_minor_alloc(dev, DRM_MINOR_RENDER);
if (ret)
goto err;
}
ret = drm_minor_alloc(dev, DRM_MINOR_PRIMARY);
if (ret)
goto err;
ret = drm_minor_alloc(dev, DRM_MINOR_PRIMARY);
if (ret)
goto err;
}
ret = drm_legacy_create_map_hash(dev);
if (ret)
......@@ -883,6 +919,10 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
if (ret)
goto err_minors;
ret = drm_minor_register(dev, DRM_MINOR_ACCEL);
if (ret)
goto err_minors;
ret = create_compat_control_link(dev);
if (ret)
goto err_minors;
......@@ -902,12 +942,13 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
driver->name, driver->major, driver->minor,
driver->patchlevel, driver->date,
dev->dev ? dev_name(dev->dev) : "virtual device",
dev->primary->index);
dev->primary ? dev->primary->index : dev->accel->index);
goto out_unlock;
err_minors:
remove_compat_control_link(dev);
drm_minor_unregister(dev, DRM_MINOR_ACCEL);
drm_minor_unregister(dev, DRM_MINOR_PRIMARY);
drm_minor_unregister(dev, DRM_MINOR_RENDER);
out_unlock:
......@@ -950,6 +991,7 @@ void drm_dev_unregister(struct drm_device *dev)
drm_legacy_rmmaps(dev);
remove_compat_control_link(dev);
drm_minor_unregister(dev, DRM_MINOR_ACCEL);
drm_minor_unregister(dev, DRM_MINOR_PRIMARY);
drm_minor_unregister(dev, DRM_MINOR_RENDER);
}
......@@ -1034,6 +1076,7 @@ static const struct file_operations drm_stub_fops = {
static void drm_core_exit(void)
{
drm_privacy_screen_lookup_exit();
accel_core_exit();
unregister_chrdev(DRM_MAJOR, "drm");
debugfs_remove(drm_debugfs_root);
drm_sysfs_destroy();
......@@ -1061,6 +1104,10 @@ static int __init drm_core_init(void)
if (ret < 0)
goto error;
ret = accel_core_init();
if (ret < 0)
goto error;
drm_privacy_screen_lookup_init();
drm_core_init_complete = true;
......
......@@ -326,7 +326,7 @@ static int drm_cpu_valid(void)
* Creates and initializes a drm_file structure for the file private data in \p
* filp and add it into the double linked list in \p dev.
*/
static int drm_open_helper(struct file *filp, struct drm_minor *minor)
int drm_open_helper(struct file *filp, struct drm_minor *minor)
{
struct drm_device *dev = minor->dev;
struct drm_file *priv;
......
......@@ -19,6 +19,7 @@
#include <linux/kdev_t.h>
#include <linux/slab.h>
#include <drm/drm_accel.h>
#include <drm/drm_connector.h>
#include <drm/drm_device.h>
#include <drm/drm_file.h>
......@@ -471,19 +472,26 @@ struct device *drm_sysfs_minor_alloc(struct drm_minor *minor)
struct device *kdev;
int r;
if (minor->type == DRM_MINOR_RENDER)
minor_str = "renderD%d";
else
minor_str = "card%d";
kdev = kzalloc(sizeof(*kdev), GFP_KERNEL);
if (!kdev)
return ERR_PTR(-ENOMEM);
device_initialize(kdev);
kdev->devt = MKDEV(DRM_MAJOR, minor->index);
kdev->class = drm_class;
kdev->type = &drm_sysfs_device_minor;
if (minor->type == DRM_MINOR_ACCEL) {
minor_str = "accel%d";
accel_set_device_instance_params(kdev, minor->index);
} else {
if (minor->type == DRM_MINOR_RENDER)
minor_str = "renderD%d";
else
minor_str = "card%d";
kdev->devt = MKDEV(DRM_MAJOR, minor->index);
kdev->class = drm_class;
kdev->type = &drm_sysfs_device_minor;
}
kdev->parent = minor->dev->dev;
kdev->release = drm_sysfs_release;
dev_set_drvdata(kdev, minor);
......
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright 2022 HabanaLabs, Ltd.
* All Rights Reserved.
*
*/
#ifndef DRM_ACCEL_H_
#define DRM_ACCEL_H_
#include <drm/drm_file.h>
#define ACCEL_MAJOR 261
#define ACCEL_MAX_MINORS 256
/**
* DRM_ACCEL_FOPS - Default drm accelerators file operations
*
* This macro provides a shorthand for setting the accelerator file ops in the
* &file_operations structure. If all you need are the default ops, use
* DEFINE_DRM_ACCEL_FOPS instead.
*/
#define DRM_ACCEL_FOPS \
.open = accel_open,\
.release = drm_release,\
.unlocked_ioctl = drm_ioctl,\
.compat_ioctl = drm_compat_ioctl,\
.poll = drm_poll,\
.read = drm_read,\
.llseek = noop_llseek
/**
* DEFINE_DRM_ACCEL_FOPS() - macro to generate file operations for accelerators drivers
* @name: name for the generated structure
*
* This macro autogenerates a suitable &struct file_operations for accelerators based
* drivers, which can be assigned to &drm_driver.fops. Note that this structure
* cannot be shared between drivers, because it contains a reference to the
* current module using THIS_MODULE.
*
* Note that the declaration is already marked as static - if you need a
* non-static version of this you're probably doing it wrong and will break the
* THIS_MODULE reference by accident.
*/
#define DEFINE_DRM_ACCEL_FOPS(name) \
static const struct file_operations name = {\
.owner = THIS_MODULE,\
DRM_ACCEL_FOPS,\
}
#if IS_ENABLED(CONFIG_DRM_ACCEL)
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_minor *minor, int minor_id);
#else
static inline void accel_core_exit(void)
{
}
static inline int __init accel_core_init(void)
{
/* Return 0 to allow drm_core_init to complete successfully */
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)
{
}
static inline void accel_debugfs_init(struct drm_minor *minor, int minor_id)
{
}
#endif /* IS_ENABLED(CONFIG_DRM_ACCEL) */
#endif /* DRM_ACCEL_H_ */
......@@ -93,6 +93,9 @@ struct drm_device {
/** @render: Render node */
struct drm_minor *render;
/** @accel: Compute Acceleration node */
struct drm_minor *accel;
/**
* @registered:
*
......
......@@ -96,6 +96,14 @@ enum drm_driver_feature {
* synchronization of command submission.
*/
DRIVER_SYNCOBJ_TIMELINE = BIT(6),
/**
* @DRIVER_COMPUTE_ACCEL:
*
* Driver supports compute acceleration devices. This flag is mutually exclusive with
* @DRIVER_RENDER and @DRIVER_MODESET. Devices that support both graphics and compute
* acceleration should be handled by two drivers that are connected using auxiliary bus.
*/
DRIVER_COMPUTE_ACCEL = BIT(7),
/* IMPORTANT: Below are all the legacy flags, add new ones above. */
......
......@@ -51,11 +51,15 @@ struct file;
/* Note that the order of this enum is ABI (it determines
* /dev/dri/renderD* numbers).
*
* Setting DRM_MINOR_ACCEL to 32 gives enough space for more drm minors to
* be implemented before we hit any future
*/
enum drm_minor_type {
DRM_MINOR_PRIMARY,
DRM_MINOR_CONTROL,
DRM_MINOR_RENDER,
DRM_MINOR_ACCEL = 32,
};
/**
......@@ -70,7 +74,7 @@ enum drm_minor_type {
struct drm_minor {
/* private: */
int index; /* Minor device number */
int type; /* Control or render */
int type; /* Control or render or accel */
struct device *kdev; /* Linux device */
struct drm_device *dev;
......@@ -397,7 +401,22 @@ static inline bool drm_is_render_client(const struct drm_file *file_priv)
return file_priv->minor->type == DRM_MINOR_RENDER;
}
/**
* drm_is_accel_client - is this an open file of the compute acceleration node
* @file_priv: DRM file
*
* Returns true if this is an open file of the compute acceleration node, i.e.
* &drm_file.minor of @file_priv is a accel minor.
*
* See also the :ref:`section on accel nodes <drm_accel_node>`.
*/
static inline bool drm_is_accel_client(const struct drm_file *file_priv)
{
return file_priv->minor->type == DRM_MINOR_ACCEL;
}
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,
size_t count, loff_t *offset);
int drm_release(struct inode *inode, struct file *filp);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment