[PATCH 7/9] accel/neutron: Add job submission IOCTL

Christian König christian.koenig at amd.com
Thu Feb 26 06:59:49 PST 2026


On 2/26/26 14:40, Ioana Ciocoi-Radulescu wrote:
> [Sie erhalten nicht häufig E-Mails von ruxandra.radulescu at nxp.com. Weitere Informationen, warum dies wichtig ist, finden Sie unter https://aka.ms/LearnAboutSenderIdentification ]
> 
> Neutron can execute a single job at a time. For now, only inference
> jobs are supported. Each job has exactly one BO associated with it.
> 
> When submitting a job, user also provides a syncobj handle on which it
> will wait for job completion.
> 
> We use the DRM GPU scheduler for job management. Large part of the job
> submission code is based on the example of the ethosu driver.
> 
> Signed-off-by: Jiwei Fu <jiwei.fu at nxp.com>
> Signed-off-by: Ioana Ciocoi-Radulescu <ruxandra.radulescu at nxp.com>
> ---
>  drivers/accel/neutron/Makefile         |   1 +
>  drivers/accel/neutron/neutron_device.c |   8 +-
>  drivers/accel/neutron/neutron_device.h |  21 ++
>  drivers/accel/neutron/neutron_driver.c |  28 ++-
>  drivers/accel/neutron/neutron_driver.h |   3 +
>  drivers/accel/neutron/neutron_job.c    | 367 +++++++++++++++++++++++++++++++++
>  drivers/accel/neutron/neutron_job.h    |  45 ++++
>  include/uapi/drm/neutron_accel.h       |  51 +++++
>  8 files changed, 519 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/accel/neutron/Makefile b/drivers/accel/neutron/Makefile
> index 192ed896a9f9..ac6dd576521c 100644
> --- a/drivers/accel/neutron/Makefile
> +++ b/drivers/accel/neutron/Makefile
> @@ -6,4 +6,5 @@ neutron-y := \
>         neutron_driver.o \
>         neutron_device.o \
>         neutron_gem.o \
> +       neutron_job.o \
>         neutron_mailbox.o
> diff --git a/drivers/accel/neutron/neutron_device.c b/drivers/accel/neutron/neutron_device.c
> index e5c09105be99..571ec906ad72 100644
> --- a/drivers/accel/neutron/neutron_device.c
> +++ b/drivers/accel/neutron/neutron_device.c
> @@ -7,6 +7,7 @@
>  #include <linux/iopoll.h>
> 
>  #include "neutron_device.h"
> +#include "neutron_job.h"
>  #include "neutron_mailbox.h"
> 
>  void neutron_enable_irq(struct neutron_device *ndev)
> @@ -32,9 +33,14 @@ void neutron_handle_irq(struct neutron_device *ndev)
>         /* Write 1 to clear */
>         writel_relaxed(appstatus & APPSTATUS_CLEAR_MASK, NEUTRON_REG(ndev, APPSTATUS));
> 
> -       if (appstatus & APPSTATUS_FAULTCAUSE_MASK)
> +       if (appstatus & APPSTATUS_FAULTCAUSE_MASK) {
>                 dev_err(ndev->dev, "Neutron halted due to fault: 0x%lx\n",
>                         FIELD_GET(APPSTATUS_FAULTCAUSE_MASK, appstatus));
> +               return neutron_job_err_handler(ndev);
> +       }
> +
> +       if (appstatus & APPSTATUS_INFDONE)
> +               neutron_job_done_handler(ndev);
>  }
> 
>  #define neutron_boot_done(appctrl) \
> diff --git a/drivers/accel/neutron/neutron_device.h b/drivers/accel/neutron/neutron_device.h
> index 8e4df7462d82..0ed72965774d 100644
> --- a/drivers/accel/neutron/neutron_device.h
> +++ b/drivers/accel/neutron/neutron_device.h
> @@ -9,8 +9,10 @@
>  #include <linux/spinlock.h>
>  #include <linux/bits.h>
>  #include <drm/drm_device.h>
> +#include <drm/gpu_scheduler.h>
> 
>  struct clk_bulk_data;
> +struct neutron_job;
> 
>  #define NEUTRON_FIRMWARE_NAME          "NeutronFirmware.elf"
> 
> @@ -92,6 +94,13 @@ enum neutron_mem_id {
>   * @clks: Neutron clocks
>   * @num_clks: Number of clocks
>   * @flags: Software flags used by driver
> + * @fence_lock: DMA fence lock
> + * @sched: GPU scheduler
> + * @sched_lock: Scheduler lock, for neutron_push_job
> + * @fence_context: Fence context
> + * @job_seqno: Job sequence number
> + * @job_lock: Job lock, for active_job handling
> + * @active_job: Currently active job
>   */
>  struct neutron_device {
>         struct drm_device base;
> @@ -103,6 +112,18 @@ struct neutron_device {
>         struct clk_bulk_data *clks;
>         int num_clks;
>         u32 flags;
> +
> +       /* For dma_fence */
> +       spinlock_t fence_lock;

I've just pushed a patch set to drm-misc-next which makes the fence_lock superflous in most cases. Just provide NULL as lock when calling to dma_fence_init().

> +       struct drm_gpu_scheduler sched;
> +       /* For neutron_push_job */
> +       struct mutex sched_lock;
> +       u64 fence_context;
> +       u64 job_seqno;
> +
> +       /* For active_job handling */
> +       struct mutex job_lock;
> +       struct neutron_job *active_job;
>  };
> 
>  #define to_neutron_device(drm) \
> diff --git a/drivers/accel/neutron/neutron_driver.c b/drivers/accel/neutron/neutron_driver.c
> index c9a18bf52037..ceae1f7e8359 100644
> --- a/drivers/accel/neutron/neutron_driver.c
> +++ b/drivers/accel/neutron/neutron_driver.c
> @@ -19,40 +19,53 @@
>  #include "neutron_device.h"
>  #include "neutron_driver.h"
>  #include "neutron_gem.h"
> +#include "neutron_job.h"
> 
>  #define NEUTRON_SUSPEND_DELAY_MS 1000
> 
>  static const struct drm_ioctl_desc neutron_drm_ioctls[] = {
>         DRM_IOCTL_DEF_DRV(NEUTRON_CREATE_BO, neutron_ioctl_create_bo, 0),
>         DRM_IOCTL_DEF_DRV(NEUTRON_SYNC_BO, neutron_ioctl_sync_bo, 0),
> +       DRM_IOCTL_DEF_DRV(NEUTRON_SUBMIT_JOB, neutron_ioctl_submit_job, 0),
>  };
> 
>  static int neutron_open(struct drm_device *drm, struct drm_file *file)
>  {
>         struct neutron_device *ndev = to_neutron_device(drm);
>         struct neutron_file_priv *npriv;
> +       int ret;
> 
>         npriv = kzalloc_obj(*npriv);
>         if (!npriv)
>                 return -ENOMEM;
> 
>         npriv->ndev = ndev;
> -       file->driver_priv = npriv;
> 
> +       ret = neutron_job_open(npriv);
> +       if (ret)
> +               goto err_free;
> +
> +       file->driver_priv = npriv;
>         return 0;
> +
> +err_free:
> +       kfree(npriv);
> +       return ret;
>  }
> 
>  static void neutron_postclose(struct drm_device *drm, struct drm_file *file)
>  {
>         struct neutron_file_priv *npriv = file->driver_priv;
> 
> +       neutron_job_close(npriv);
>         kfree(npriv);
>  }
> 
>  DEFINE_DRM_ACCEL_FOPS(neutron_drm_driver_fops);
> 
>  static const struct drm_driver neutron_drm_driver = {
> -       .driver_features        = DRIVER_COMPUTE_ACCEL | DRIVER_GEM,
> +       .driver_features        = DRIVER_COMPUTE_ACCEL | DRIVER_GEM |
> +                                 DRIVER_SYNCOBJ,
>         .name                   = "neutron",
>         .desc                   = "NXP Neutron driver",
>         .major                  = 1,
> @@ -151,19 +164,25 @@ static int neutron_probe(struct platform_device *pdev)
>                 return ret;
>         }
> 
> -       ret = devm_pm_runtime_enable(dev);
> +       ret = neutron_job_init(ndev);
>         if (ret)
>                 goto free_reserved;
> 
> +       ret = devm_pm_runtime_enable(dev);
> +       if (ret)
> +               goto free_job;
> +
>         pm_runtime_set_autosuspend_delay(dev, NEUTRON_SUSPEND_DELAY_MS);
>         pm_runtime_use_autosuspend(dev);
> 
>         ret = drm_dev_register(&ndev->base, 0);
>         if (ret)
> -               goto free_reserved;
> +               goto free_job;
> 
>         return 0;
> 
> +free_job:
> +       neutron_job_fini(ndev);
>  free_reserved:
>         of_reserved_mem_device_release(&pdev->dev);
> 
> @@ -175,6 +194,7 @@ static void neutron_remove(struct platform_device *pdev)
>         struct neutron_device *ndev = platform_get_drvdata(pdev);
> 
>         drm_dev_unregister(&ndev->base);
> +       neutron_job_fini(ndev);
>         of_reserved_mem_device_release(&pdev->dev);
>  }
> 
> diff --git a/drivers/accel/neutron/neutron_driver.h b/drivers/accel/neutron/neutron_driver.h
> index cd52b5eb2d27..b709de74105a 100644
> --- a/drivers/accel/neutron/neutron_driver.h
> +++ b/drivers/accel/neutron/neutron_driver.h
> @@ -4,10 +4,13 @@
>  #ifndef __NEUTRON_DRIVER_H__
>  #define __NEUTRON_DRIVER_H__
> 
> +#include <drm/gpu_scheduler.h>
> +
>  struct neutron_device;
> 
>  struct neutron_file_priv {
>         struct neutron_device *ndev;
> +       struct drm_sched_entity sched_entity;
>  };
> 
>  #endif /* __NEUTRON_DRIVER_H__ */
> diff --git a/drivers/accel/neutron/neutron_job.c b/drivers/accel/neutron/neutron_job.c
> new file mode 100644
> index 000000000000..316e361166a2
> --- /dev/null
> +++ b/drivers/accel/neutron/neutron_job.c
> @@ -0,0 +1,367 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/* Copyright 2025-2026 NXP */
> +
> +#include <linux/delay.h>
> +#include <linux/pm_runtime.h>
> +#include <drm/drm_file.h>
> +#include <drm/drm_print.h>
> +#include <drm/drm_gem_dma_helper.h>
> +#include <drm/neutron_accel.h>
> +
> +#include "neutron_driver.h"
> +#include "neutron_device.h"
> +#include "neutron_gem.h"
> +#include "neutron_mailbox.h"
> +#include "neutron_job.h"
> +
> +#define NEUTRON_JOB_TIMEOUT_MS 5000
> +
> +static const char *neutron_fence_get_driver_name(struct dma_fence *fence)
> +{
> +       return "neutron";
> +}
> +
> +static const char *neutron_fence_get_timeline_name(struct dma_fence *fence)
> +{
> +       return "neutron-npu";
> +}
> +
> +static const struct dma_fence_ops neutron_fence_ops = {
> +       .get_driver_name = neutron_fence_get_driver_name,
> +       .get_timeline_name = neutron_fence_get_timeline_name,
> +};
> +
> +static void neutron_hw_submit(struct neutron_job *job)
> +{
> +       struct neutron_device *ndev = job->ndev;
> +       struct neutron_mbox_cmd cmd = {0};
> +       u32 base_l, base_h;
> +       u64 base_addr;
> +       int ret;
> +
> +       switch (job->type) {
> +       case DRM_NEUTRON_JOB_INFERENCE:
> +               cmd.id = NEUTRON_CMD_INFERENCE;
> +               cmd.args[0] = job->inference.tensor_offset;
> +               cmd.args[1] = job->inference.microcode_offset;
> +               cmd.args[2] = job->inference.tensor_count;
> +               break;
> +       default:
> +               dev_WARN(ndev->dev, "Unknown job type: %d\n", job->type);
> +               return;
> +       }
> +
> +       base_addr = to_drm_gem_dma_obj(job->bo)->dma_addr;
> +       base_l = lower_32_bits(base_addr);
> +       base_h = upper_32_bits(base_addr);
> +
> +       writel_relaxed(base_l, NEUTRON_REG(ndev, BASEDDRL));
> +       writel_relaxed(base_l, NEUTRON_REG(ndev, BASEINOUTL));
> +       writel_relaxed(base_l, NEUTRON_REG(ndev, BASESPILLL));
> +       writel_relaxed(base_h, NEUTRON_REG(ndev, BASEDDRH));
> +       writel_relaxed(base_h, NEUTRON_REG(ndev, BASEINOUTH));
> +       writel_relaxed(base_h, NEUTRON_REG(ndev, BASESPILLH));
> +
> +       ret = neutron_mbox_send_cmd(ndev, &cmd);
> +       if (ret) {
> +               /* Nothing we can do here, we'll reset the device on timeout */
> +               dev_err(ndev->dev, "Failed to submit job, device is busy\n");
> +       }
> +}
> +
> +void neutron_job_err_handler(struct neutron_device *ndev)
> +{
> +       guard(mutex)(&ndev->job_lock);
> +
> +       if (ndev->active_job)
> +               drm_sched_fault(&ndev->sched);
> +}
> +
> +void neutron_job_done_handler(struct neutron_device *ndev)
> +{
> +       struct neutron_mbox_state state;
> +
> +       neutron_mbox_read_state(ndev, &state);
> +       if (state.status != NEUTRON_FW_STATUS_DONE) {
> +               dev_err(ndev->dev, "Inconsistent firmware state: status 0x%x, err 0x%x\n",
> +                       state.status, state.err_code);
> +               return neutron_job_err_handler(ndev);
> +       }
> +
> +       if (state.err_code != 0)
> +               dev_warn(ndev->dev, "Job finished with error: 0x%x\n",
> +                        state.err_code);

Not mandatory but you might also want to forward that as error to your dma_fence, see dma_fence_set_error(). 

> +
> +       /* Reset Neutron internal state to prepare for next inference */
> +       neutron_mbox_reset_state(ndev);
> +
> +       scoped_guard(mutex, &ndev->job_lock) {
> +               if (ndev->active_job) {
> +                       dma_fence_signal(ndev->active_job->neutron_fence);
> +                       ndev->active_job = NULL;
> +               }
> +       }
> +}
> +
> +static void neutron_cleanup_job(struct kref *ref)
> +{
> +       struct neutron_job *job = container_of(ref, struct neutron_job, refcnt);
> +
> +       pm_runtime_put_autosuspend(job->ndev->base.dev);
> +
> +       dma_fence_put(job->neutron_fence);
> +       dma_fence_put(job->sched_fence);
> +       drm_gem_object_put(job->bo);
> +       drm_syncobj_put(job->syncobj);
> +
> +       kfree(job);
> +}
> +
> +static void neutron_put_job(struct neutron_job *job)
> +{
> +       kref_put(&job->refcnt, neutron_cleanup_job);
> +}
> +
> +static void neutron_free_job(struct drm_sched_job *sched_job)
> +{
> +       struct neutron_job *job = to_neutron_job(sched_job);
> +
> +       drm_sched_job_cleanup(sched_job);
> +       neutron_put_job(job);
> +}
> +
> +static struct dma_fence *neutron_run_job(struct drm_sched_job *sched_job)
> +{
> +       struct neutron_job *job = to_neutron_job(sched_job);
> +       struct dma_fence *fence = job->neutron_fence;
> +       struct neutron_device *ndev = job->ndev;
> +
> +       if (unlikely(job->base.s_fence->finished.error))
> +               return NULL;
> +
> +       dma_fence_init(fence, &neutron_fence_ops, &ndev->fence_lock,
> +                      ndev->fence_context, ++ndev->job_seqno);
> +       dma_fence_get(fence);
> +
> +       scoped_guard(mutex, &ndev->job_lock) {
> +               ndev->active_job = job;
> +               neutron_hw_submit(job);
> +       }
> +
> +       return fence;
> +}
> +
> +static enum drm_gpu_sched_stat neutron_timedout_job(struct drm_sched_job *sched_job)
> +{
> +       struct neutron_job *job = to_neutron_job(sched_job);
> +       struct neutron_device *ndev = job->ndev;
> +       struct neutron_mbox_state state;
> +
> +       /* We assume Neutron is stuck, retrieve current state and reset */
> +       neutron_mbox_read_state(ndev, &state);
> +       dev_err(ndev->dev, "Neutron timedout, status: 0x%x, err: 0x%x\n",
> +               state.status, state.err_code);
> +
> +       drm_sched_stop(&ndev->sched, sched_job);
> +
> +       scoped_guard(mutex, &ndev->job_lock)
> +               ndev->active_job = NULL;
> +
> +       pm_runtime_force_suspend(ndev->dev);
> +       pm_runtime_force_resume(ndev->dev);
> +
> +       drm_sched_start(&ndev->sched, 0);
> +
> +       return DRM_GPU_SCHED_STAT_RESET;
> +}
> +
> +static void neutron_cancel_job(struct drm_sched_job *sched_job)
> +{
> +       struct neutron_job *job = to_neutron_job(sched_job);
> +       struct neutron_device *ndev = job->ndev;
> +
> +       guard(mutex)(&ndev->job_lock);
> +
> +       if (!dma_fence_is_signaled(job->neutron_fence)) {
> +               dma_fence_set_error(job->neutron_fence, -ECANCELED);
> +               dma_fence_signal(job->neutron_fence);
> +       }
> +}
> +
> +static const struct drm_sched_backend_ops neutron_sched_ops = {
> +       .run_job = neutron_run_job,
> +       .free_job = neutron_free_job,
> +       .timedout_job = neutron_timedout_job,
> +       .cancel_job = neutron_cancel_job,
> +};
> +
> +int neutron_job_init(struct neutron_device *ndev)
> +{
> +       const struct drm_sched_init_args args = {
> +               .ops = &neutron_sched_ops,
> +               .num_rqs = DRM_SCHED_PRIORITY_COUNT,
> +               .credit_limit = 1,
> +               .timeout = msecs_to_jiffies(NEUTRON_JOB_TIMEOUT_MS),
> +               .name = dev_name(ndev->dev),
> +               .dev = ndev->dev,
> +       };
> +       int ret;
> +
> +       ret = devm_mutex_init(ndev->dev, &ndev->sched_lock);
> +       if (ret)
> +               return ret;
> +       ret = devm_mutex_init(ndev->dev, &ndev->job_lock);
> +       if (ret)
> +               return ret;
> +       spin_lock_init(&ndev->fence_lock);
> +
> +       ndev->fence_context = dma_fence_context_alloc(1);
> +
> +       ret = drm_sched_init(&ndev->sched, &args);
> +       if (ret)
> +               dev_err(ndev->dev, "Error creating DRM scheduler\n");
> +
> +       return ret;
> +}
> +
> +void neutron_job_fini(struct neutron_device *ndev)
> +{
> +       drm_sched_fini(&ndev->sched);
> +}
> +
> +int neutron_job_open(struct neutron_file_priv *npriv)
> +{
> +       struct neutron_device *ndev = npriv->ndev;
> +       struct drm_gpu_scheduler *sched = &ndev->sched;
> +       int ret;
> +
> +       ret = drm_sched_entity_init(&npriv->sched_entity,
> +                                   DRM_SCHED_PRIORITY_NORMAL,
> +                                   &sched, 1, NULL);
> +       if (ret)
> +               dev_err(ndev->dev, "Error creating scheduler entity\n");
> +
> +       return ret;
> +}
> +
> +void neutron_job_close(struct neutron_file_priv *npriv)
> +{
> +       drm_sched_entity_destroy(&npriv->sched_entity);
> +}
> +
> +static int neutron_push_job(struct neutron_job *job)
> +{
> +       struct neutron_device *ndev = job->ndev;
> +       struct ww_acquire_ctx acquire_ctx;
> +       int ret;
> +
> +       ret = drm_gem_lock_reservations(&job->bo, 1, &acquire_ctx);
> +       if (ret)
> +               return ret;
> +
> +       ret = dma_resv_reserve_fences(job->bo->resv, 1);
> +       if (ret)
> +               goto out_unlock_res;
> +
> +       ret = drm_sched_job_add_implicit_dependencies(&job->base, job->bo, true);
> +       if (ret)
> +               goto out_unlock_res;
> +
> +       ret = pm_runtime_resume_and_get(ndev->base.dev);
> +       if (ret)
> +               goto out_unlock_res;
> +
> +       scoped_guard(mutex, &ndev->sched_lock) {
> +               drm_sched_job_arm(&job->base);
> +
> +               job->sched_fence = dma_fence_get(&job->base.s_fence->finished);
> +               drm_syncobj_replace_fence(job->syncobj, job->sched_fence);
> +
> +               kref_get(&job->refcnt);
> +               drm_sched_entity_push_job(&job->base);
> +
> +               dma_resv_add_fence(job->bo->resv, job->sched_fence,
> +                                  DMA_RESV_USAGE_WRITE);
> +       }
> +
> +out_unlock_res:
> +       drm_gem_unlock_reservations(&job->bo, 1, &acquire_ctx);
> +
> +       return ret;
> +}
> +
> +int neutron_ioctl_submit_job(struct drm_device *drm, void *data, struct drm_file *filp)
> +{
> +       struct neutron_device *ndev = to_neutron_device(drm);
> +       struct neutron_file_priv *npriv = filp->driver_priv;
> +       struct drm_neutron_submit_job *args = data;
> +       struct neutron_job *job;
> +       int ret;
> +
> +       if (args->pad)
> +               return -EINVAL;
> +
> +       job = kzalloc_obj(*job);
> +       if (!job)
> +               return -ENOMEM;
> +
> +       job->ndev = ndev;
> +       kref_init(&job->refcnt);
> +
> +       job->neutron_fence = kzalloc_obj(*job->neutron_fence);
> +       if (!job->neutron_fence) {
> +               ret = -ENOMEM;
> +               goto out_free_job;
> +       }
> +
> +       switch (args->type) {
> +       case DRM_NEUTRON_JOB_INFERENCE:
> +               memcpy(&job->inference, &args->inference,
> +                      sizeof(args->inference));
> +               break;
> +       default:
> +               dev_dbg(ndev->dev, "Invalid job type %d\n", args->type);
> +               ret = -EINVAL;
> +               goto out_free_fence;
> +       }
> +
> +       job->bo = drm_gem_object_lookup(filp, args->bo_handle);
> +       if (!job->bo) {
> +               dev_dbg(ndev->dev, "Invalid BO handle\n");
> +               ret = -ENOENT;
> +               goto out_free_fence;
> +       }
> +
> +       job->syncobj = drm_syncobj_find(filp, args->syncobj_handle);
> +       if (!job->syncobj) {
> +               dev_dbg(ndev->dev, "Invalid syncobj handle\n");
> +               ret = -ENOENT;
> +               goto out_put_gem;
> +       }
> +
> +       ret = drm_sched_job_init(&job->base, &npriv->sched_entity, 1, NULL,
> +                                filp->client_id);
> +       if (ret)
> +               goto out_put_syncobj;
> +
> +       ret = neutron_push_job(job);
> +       if (ret)
> +               goto out_sched_cleanup;
> +
> +       neutron_put_job(job);
> +
> +       return 0;
> +
> +out_sched_cleanup:
> +       drm_sched_job_cleanup(&job->base);
> +out_put_syncobj:
> +       drm_syncobj_put(job->syncobj);
> +out_put_gem:
> +       drm_gem_object_put(job->bo);
> +out_free_fence:
> +       kfree(job->neutron_fence);
> +out_free_job:
> +       kfree(job);
> +
> +       return ret;
> +}
> diff --git a/drivers/accel/neutron/neutron_job.h b/drivers/accel/neutron/neutron_job.h
> new file mode 100644
> index 000000000000..bb7773aeb218
> --- /dev/null
> +++ b/drivers/accel/neutron/neutron_job.h
> @@ -0,0 +1,45 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/* Copyright 2025-2026 NXP */
> +
> +#ifndef __NEUTRON_JOB_H__
> +#define __NEUTRON_JOB_H__
> +
> +#include <linux/kref.h>
> +#include <drm/drm_gem.h>
> +#include <drm/drm_syncobj.h>
> +#include <drm/gpu_scheduler.h>
> +#include <drm/neutron_accel.h>
> +
> +#include "neutron_driver.h"
> +
> +struct neutron_device;
> +struct neutron_file_priv;
> +
> +struct neutron_job {
> +       struct drm_sched_job base;
> +       struct neutron_device *ndev;
> +       struct dma_fence *neutron_fence;

> +       struct dma_fence *sched_fence;

That looks superflous to me. You should always have the scheduler fence through the base.

> +       struct drm_syncobj *syncobj;

Why do you want to keep the syncobj around?


Apart from those notes looks pretty good to me, but I'm a bit disapointed that there isn't any DMA-buf support to review :)

Regards,
Christian.

> +       struct drm_gem_object *bo;
> +       enum drm_neutron_job_type type;
> +       union {
> +               struct drm_neutron_inference_job inference;
> +       };
> +       struct kref refcnt;
> +};
> +
> +#define to_neutron_job(job) \
> +       container_of(job, struct neutron_job, base)
> +
> +int neutron_job_init(struct neutron_device *dev);
> +void neutron_job_fini(struct neutron_device *dev);
> +int neutron_job_open(struct neutron_file_priv *npriv);
> +void neutron_job_close(struct neutron_file_priv *npriv);
> +
> +void neutron_job_done_handler(struct neutron_device *dev);
> +void neutron_job_err_handler(struct neutron_device *dev);
> +
> +int neutron_ioctl_submit_job(struct drm_device *dev, void *data, struct drm_file *filp);
> +
> +#endif /* __NEUTRON_JOB_H__ */
> diff --git a/include/uapi/drm/neutron_accel.h b/include/uapi/drm/neutron_accel.h
> index 2f5639f2e0e8..a9e5682709d2 100644
> --- a/include/uapi/drm/neutron_accel.h
> +++ b/include/uapi/drm/neutron_accel.h
> @@ -15,10 +15,12 @@ extern "C" {
>   *
>   * @DRM_NEUTRON_CREATE_BO: Create a buffer object
>   * @DRM_NEUTRON_SYNC_BO: Sync (parts of) the buffer object memory
> + * @DRM_NEUTRON_SUBMIT_JOB: Submit a job to the device
>   */
>  enum drm_neutron_ioctl {
>         DRM_NEUTRON_CREATE_BO = 0,
>         DRM_NEUTRON_SYNC_BO,
> +       DRM_NEUTRON_SUBMIT_JOB,
>  };
> 
>  /**
> @@ -64,6 +66,51 @@ struct drm_neutron_sync_bo {
>         __u64 offset;
>  };
> 
> +/**
> + * enum drm_neutron_job_type - Type of job to submit to Neutron device
> + *
> + * @DRM_NEUTRON_JOB_INFERENCE: Inference job
> + */
> +enum drm_neutron_job_type {
> +       DRM_NEUTRON_JOB_INFERENCE = 0,
> +};
> +
> +/**
> + * struct drm_neutron_inference_job - Inference job descriptor
> + *
> + * @tensor_offset: Offset of tensor array inside job BO
> + * @microcode_offset: Microcode offset inside BO
> + * @tensor_count: Number of valid tensors
> + * @pad: MBZ
> + */
> +struct drm_neutron_inference_job {
> +       __u32 tensor_offset;
> +       __u32 microcode_offset;
> +       __u32 tensor_count;
> +       __u32 pad[5];
> +};
> +
> +/**
> + * struct drm_neutron_submit_job - Submit a job to Neutron device
> + *
> + * @type: Job type, one of enum drm_neutron_job_type
> + * @bo_handle: BO handle for this job
> + * @inference: Inference job descriptor (when type is DRM_NEUTRON_JOB_INFERENCE)
> + * @reserved: Reserved for future job types
> + * @syncobj_handle: Handle of syncobj on which user waits for job completion
> + * @pad: MBZ
> + */
> +struct drm_neutron_submit_job {
> +       __u32 type;
> +       __u32 bo_handle;
> +       union {
> +               struct drm_neutron_inference_job inference;
> +               __u32 reserved[8];
> +       };
> +       __u32 syncobj_handle;
> +       __u32 pad;
> +};
> +
>  #define DRM_IOCTL_NEUTRON_CREATE_BO \
>         DRM_IOWR(DRM_COMMAND_BASE + DRM_NEUTRON_CREATE_BO, \
>                  struct drm_neutron_create_bo)
> @@ -72,6 +119,10 @@ struct drm_neutron_sync_bo {
>         DRM_IOWR(DRM_COMMAND_BASE + DRM_NEUTRON_SYNC_BO, \
>                  struct drm_neutron_sync_bo)
> 
> +#define DRM_IOCTL_NEUTRON_SUBMIT_JOB \
> +       DRM_IOWR(DRM_COMMAND_BASE + DRM_NEUTRON_SUBMIT_JOB, \
> +                struct drm_neutron_submit_job)
> +
>  #if defined(__cplusplus)
>  }
>  #endif
> 
> --
> 2.34.1
> 




More information about the linux-arm-kernel mailing list