mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
accel/rocket: Add job submission IOCTL
Using the DRM GPU scheduler infrastructure, with a scheduler for each core. Userspace can decide for a series of tasks to be executed sequentially in the same core, so SRAM locality can be taken advantage of. The job submission code was initially based on Panfrost. v2: - Remove hardcoded number of cores - Misc. style fixes (Jeffrey Hugo) - Repack IOCTL struct (Jeffrey Hugo) v3: - Adapt to a split of the register block in the DT bindings (Nicolas Frattaroli) - Make use of GPL-2.0-only for the copyright notice (Jeff Hugo) - Use drm_* logging functions (Thomas Zimmermann) - Rename reg i/o macros (Thomas Zimmermann) - Add padding to ioctls and check for zero (Jeff Hugo) - Improve error handling (Nicolas Frattaroli) v6: - Use mutexes guard (Markus Elfring) - Use u64_to_user_ptr (Jeff Hugo) - Drop rocket_fence (Rob Herring) v7: - Assign its own IOMMU domain to each client, for isolation (Daniel Stone and Robin Murphy) v8: - Use reset lines to reset the cores (Robin Murphy) - Use the macros to compute the values for the bitfields (Robin Murphy) - More descriptive name for the IRQ (Robin Murphy) - Simplify job interrupt handing (Robin Murphy) - Correctly acquire a reference to the IOMMU (Robin Murphy) - Specify the size of the embedded structs in the IOCTLs for future extensibility (Rob Herring) - Expose only 32 bits for the address of the regcmd BO (Robin Murphy) Tested-by: Heiko Stuebner <heiko@sntech.de> Reviewed-by: Jeff Hugo <jeff.hugo@oss.qualcomm.com> Signed-off-by: Tomeu Vizoso <tomeu@tomeuvizoso.net> Signed-off-by: Jeff Hugo <jeff.hugo@oss.qualcomm.com> Link: https://lore.kernel.org/r/20250721-6-10-rocket-v9-4-77ebd484941e@tomeuvizoso.net
This commit is contained in:
@@ -6,4 +6,5 @@ rocket-y := \
|
||||
rocket_core.o \
|
||||
rocket_device.o \
|
||||
rocket_drv.o \
|
||||
rocket_gem.o
|
||||
rocket_gem.o \
|
||||
rocket_job.o
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include "rocket_core.h"
|
||||
#include "rocket_job.h"
|
||||
|
||||
int rocket_core_init(struct rocket_core *core)
|
||||
{
|
||||
@@ -57,6 +58,10 @@ int rocket_core_init(struct rocket_core *core)
|
||||
|
||||
core->iommu_group = iommu_group_get(dev);
|
||||
|
||||
err = rocket_job_init(core);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
|
||||
/*
|
||||
@@ -70,6 +75,10 @@ int rocket_core_init(struct rocket_core *core)
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
err = pm_runtime_get_sync(dev);
|
||||
if (err) {
|
||||
rocket_job_fini(core);
|
||||
return err;
|
||||
}
|
||||
|
||||
version = rocket_pc_readl(core, VERSION);
|
||||
version += rocket_pc_readl(core, VERSION_NUM) & 0xffff;
|
||||
@@ -88,6 +97,7 @@ void rocket_core_fini(struct rocket_core *core)
|
||||
pm_runtime_disable(core->dev);
|
||||
iommu_group_put(core->iommu_group);
|
||||
core->iommu_group = NULL;
|
||||
rocket_job_fini(core);
|
||||
}
|
||||
|
||||
void rocket_core_reset(struct rocket_core *core)
|
||||
|
||||
@@ -40,6 +40,21 @@ struct rocket_core {
|
||||
struct reset_control_bulk_data resets[2];
|
||||
|
||||
struct iommu_group *iommu_group;
|
||||
|
||||
struct mutex job_lock;
|
||||
struct rocket_job *in_flight_job;
|
||||
|
||||
spinlock_t fence_lock;
|
||||
|
||||
struct {
|
||||
struct workqueue_struct *wq;
|
||||
struct work_struct work;
|
||||
atomic_t pending;
|
||||
} reset;
|
||||
|
||||
struct drm_gpu_scheduler sched;
|
||||
u64 fence_context;
|
||||
u64 emit_seqno;
|
||||
};
|
||||
|
||||
int rocket_core_init(struct rocket_core *core);
|
||||
|
||||
@@ -41,6 +41,10 @@ struct rocket_device *rocket_device_init(struct platform_device *pdev,
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
err = devm_mutex_init(dev, &rdev->sched_lock);
|
||||
if (err)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
err = drm_dev_register(ddev, 0);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
struct rocket_device {
|
||||
struct drm_device ddev;
|
||||
|
||||
struct mutex sched_lock;
|
||||
|
||||
struct rocket_core *cores;
|
||||
unsigned int num_cores;
|
||||
};
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "rocket_drv.h"
|
||||
#include "rocket_gem.h"
|
||||
#include "rocket_job.h"
|
||||
|
||||
/*
|
||||
* Facade device, used to expose a single DRM device to userspace, that
|
||||
@@ -97,8 +98,16 @@ rocket_open(struct drm_device *dev, struct drm_file *file)
|
||||
drm_mm_init(&rocket_priv->mm, start, end - start + 1);
|
||||
mutex_init(&rocket_priv->mm_lock);
|
||||
|
||||
ret = rocket_job_open(rocket_priv);
|
||||
if (ret)
|
||||
goto err_mm_takedown;
|
||||
|
||||
return 0;
|
||||
|
||||
err_mm_takedown:
|
||||
mutex_destroy(&rocket_priv->mm_lock);
|
||||
drm_mm_takedown(&rocket_priv->mm);
|
||||
rocket_iommu_domain_put(rocket_priv->domain);
|
||||
err_free:
|
||||
kfree(rocket_priv);
|
||||
err_put_mod:
|
||||
@@ -111,6 +120,7 @@ rocket_postclose(struct drm_device *dev, struct drm_file *file)
|
||||
{
|
||||
struct rocket_file_priv *rocket_priv = file->driver_priv;
|
||||
|
||||
rocket_job_close(rocket_priv);
|
||||
mutex_destroy(&rocket_priv->mm_lock);
|
||||
drm_mm_takedown(&rocket_priv->mm);
|
||||
rocket_iommu_domain_put(rocket_priv->domain);
|
||||
@@ -123,6 +133,7 @@ static const struct drm_ioctl_desc rocket_drm_driver_ioctls[] = {
|
||||
DRM_IOCTL_DEF_DRV(ROCKET_##n, rocket_ioctl_##func, 0)
|
||||
|
||||
ROCKET_IOCTL(CREATE_BO, create_bo),
|
||||
ROCKET_IOCTL(SUBMIT, submit),
|
||||
};
|
||||
|
||||
DEFINE_DRM_ACCEL_FOPS(rocket_accel_driver_fops);
|
||||
@@ -230,6 +241,9 @@ static int rocket_device_runtime_suspend(struct device *dev)
|
||||
if (core < 0)
|
||||
return -ENODEV;
|
||||
|
||||
if (!rocket_job_is_idle(&rdev->cores[core]))
|
||||
return -EBUSY;
|
||||
|
||||
clk_bulk_disable_unprepare(ARRAY_SIZE(rdev->cores[core].clks), rdev->cores[core].clks);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#define __ROCKET_DRV_H__
|
||||
|
||||
#include <drm/drm_mm.h>
|
||||
#include <drm/gpu_scheduler.h>
|
||||
|
||||
#include "rocket_device.h"
|
||||
|
||||
@@ -19,6 +20,8 @@ struct rocket_file_priv {
|
||||
struct rocket_iommu_domain *domain;
|
||||
struct drm_mm mm;
|
||||
struct mutex mm_lock;
|
||||
|
||||
struct drm_sched_entity sched_entity;
|
||||
};
|
||||
|
||||
struct rocket_iommu_domain *rocket_iommu_domain_get(struct rocket_file_priv *rocket_priv);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,52 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Copyright 2024-2025 Tomeu Vizoso <tomeu@tomeuvizoso.net> */
|
||||
|
||||
#ifndef __ROCKET_JOB_H__
|
||||
#define __ROCKET_JOB_H__
|
||||
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/gpu_scheduler.h>
|
||||
|
||||
#include "rocket_core.h"
|
||||
#include "rocket_drv.h"
|
||||
|
||||
struct rocket_task {
|
||||
u64 regcmd;
|
||||
u32 regcmd_count;
|
||||
};
|
||||
|
||||
struct rocket_job {
|
||||
struct drm_sched_job base;
|
||||
|
||||
struct rocket_device *rdev;
|
||||
|
||||
struct drm_gem_object **in_bos;
|
||||
struct drm_gem_object **out_bos;
|
||||
|
||||
u32 in_bo_count;
|
||||
u32 out_bo_count;
|
||||
|
||||
struct rocket_task *tasks;
|
||||
u32 task_count;
|
||||
u32 next_task_idx;
|
||||
|
||||
/* Fence to be signaled by drm-sched once its done with the job */
|
||||
struct dma_fence *inference_done_fence;
|
||||
|
||||
/* Fence to be signaled by IRQ handler when the job is complete. */
|
||||
struct dma_fence *done_fence;
|
||||
|
||||
struct rocket_iommu_domain *domain;
|
||||
|
||||
struct kref refcount;
|
||||
};
|
||||
|
||||
int rocket_ioctl_submit(struct drm_device *dev, void *data, struct drm_file *file);
|
||||
|
||||
int rocket_job_init(struct rocket_core *core);
|
||||
void rocket_job_fini(struct rocket_core *core);
|
||||
int rocket_job_open(struct rocket_file_priv *rocket_priv);
|
||||
void rocket_job_close(struct rocket_file_priv *rocket_priv);
|
||||
int rocket_job_is_idle(struct rocket_core *core);
|
||||
|
||||
#endif
|
||||
@@ -12,8 +12,10 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#define DRM_ROCKET_CREATE_BO 0x00
|
||||
#define DRM_ROCKET_SUBMIT 0x01
|
||||
|
||||
#define DRM_IOCTL_ROCKET_CREATE_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_ROCKET_CREATE_BO, struct drm_rocket_create_bo)
|
||||
#define DRM_IOCTL_ROCKET_SUBMIT DRM_IOW(DRM_COMMAND_BASE + DRM_ROCKET_SUBMIT, struct drm_rocket_submit)
|
||||
|
||||
/**
|
||||
* struct drm_rocket_create_bo - ioctl argument for creating Rocket BOs.
|
||||
@@ -37,6 +39,68 @@ struct drm_rocket_create_bo {
|
||||
__u64 offset;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_rocket_task - A task to be run on the NPU
|
||||
*
|
||||
* A task is the smallest unit of work that can be run on the NPU.
|
||||
*/
|
||||
struct drm_rocket_task {
|
||||
/** Input: DMA address to NPU mapping of register command buffer */
|
||||
__u32 regcmd;
|
||||
|
||||
/** Input: Number of commands in the register command buffer */
|
||||
__u32 regcmd_count;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_rocket_job - A job to be run on the NPU
|
||||
*
|
||||
* The kernel will schedule the execution of this job taking into account its
|
||||
* dependencies with other jobs. All tasks in the same job will be executed
|
||||
* sequentially on the same core, to benefit from memory residency in SRAM.
|
||||
*/
|
||||
struct drm_rocket_job {
|
||||
/** Input: Pointer to an array of struct drm_rocket_task. */
|
||||
__u64 tasks;
|
||||
|
||||
/** Input: Pointer to a u32 array of the BOs that are read by the job. */
|
||||
__u64 in_bo_handles;
|
||||
|
||||
/** Input: Pointer to a u32 array of the BOs that are written to by the job. */
|
||||
__u64 out_bo_handles;
|
||||
|
||||
/** Input: Number of tasks passed in. */
|
||||
__u32 task_count;
|
||||
|
||||
/** Input: Size in bytes of the structs in the @tasks field. */
|
||||
__u32 task_struct_size;
|
||||
|
||||
/** Input: Number of input BO handles passed in (size is that times 4). */
|
||||
__u32 in_bo_handle_count;
|
||||
|
||||
/** Input: Number of output BO handles passed in (size is that times 4). */
|
||||
__u32 out_bo_handle_count;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_rocket_submit - ioctl argument for submitting commands to the NPU.
|
||||
*
|
||||
* The kernel will schedule the execution of these jobs in dependency order.
|
||||
*/
|
||||
struct drm_rocket_submit {
|
||||
/** Input: Pointer to an array of struct drm_rocket_job. */
|
||||
__u64 jobs;
|
||||
|
||||
/** Input: Number of jobs passed in. */
|
||||
__u32 job_count;
|
||||
|
||||
/** Input: Size in bytes of the structs in the @jobs field. */
|
||||
__u32 job_struct_size;
|
||||
|
||||
/** Reserved, must be zero. */
|
||||
__u64 reserved;
|
||||
};
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user