#ifndef PVR_CONTEXT_H
#define PVR_CONTEXT_H
#include <drm/gpu_scheduler.h>
#include <linux/compiler_attributes.h>
#include <linux/dma-fence.h>
#include <linux/kref.h>
#include <linux/types.h>
#include <linux/xarray.h>
#include <uapi/drm/pvr_drm.h>
#include "pvr_cccb.h"
#include "pvr_device.h"
#include "pvr_queue.h"
struct pvr_fw_object;
enum pvr_context_priority {
PVR_CTX_PRIORITY_LOW = 0,
PVR_CTX_PRIORITY_MEDIUM,
PVR_CTX_PRIORITY_HIGH,
};
struct pvr_context {
struct kref ref_count;
struct pvr_device *pvr_dev;
struct pvr_vm_context *vm_ctx;
enum drm_pvr_ctx_type type;
u32 flags;
enum pvr_context_priority priority;
struct pvr_fw_object *fw_obj;
void *data;
u32 data_size;
u32 ctx_id;
atomic_t faulty;
union {
struct {
struct pvr_queue *geometry;
struct pvr_queue *fragment;
};
struct pvr_queue *compute;
struct pvr_queue *transfer;
} queues;
struct list_head file_link;
};
static __always_inline struct pvr_queue *
pvr_context_get_queue_for_job(struct pvr_context *ctx, enum drm_pvr_job_type type)
{
switch (type) {
case DRM_PVR_JOB_TYPE_GEOMETRY:
return ctx->type == DRM_PVR_CTX_TYPE_RENDER ? ctx->queues.geometry : NULL;
case DRM_PVR_JOB_TYPE_FRAGMENT:
return ctx->type == DRM_PVR_CTX_TYPE_RENDER ? ctx->queues.fragment : NULL;
case DRM_PVR_JOB_TYPE_COMPUTE:
return ctx->type == DRM_PVR_CTX_TYPE_COMPUTE ? ctx->queues.compute : NULL;
case DRM_PVR_JOB_TYPE_TRANSFER_FRAG:
return ctx->type == DRM_PVR_CTX_TYPE_TRANSFER_FRAG ? ctx->queues.transfer : NULL;
}
return NULL;
}
static __always_inline struct pvr_context *
pvr_context_get(struct pvr_context *ctx)
{
if (ctx)
kref_get(&ctx->ref_count);
return ctx;
}
static __always_inline bool
pvr_context_get_if_referenced(struct pvr_context *ctx)
{
return ctx != NULL && kref_get_unless_zero(&ctx->ref_count) != 0;
}
static __always_inline struct pvr_context *
pvr_context_lookup(struct pvr_file *pvr_file, u32 handle)
{
struct pvr_context *ctx;
xa_lock(&pvr_file->ctx_handles);
ctx = pvr_context_get(xa_load(&pvr_file->ctx_handles, handle));
xa_unlock(&pvr_file->ctx_handles);
return ctx;
}
static __always_inline struct pvr_context *
pvr_context_lookup_id(struct pvr_device *pvr_dev, u32 id)
{
struct pvr_context *ctx;
xa_lock(&pvr_dev->ctx_ids);
ctx = xa_load(&pvr_dev->ctx_ids, id);
if (!kref_get_unless_zero(&ctx->ref_count))
ctx = NULL;
xa_unlock(&pvr_dev->ctx_ids);
return ctx;
}
static __always_inline u32
pvr_context_get_fw_addr(struct pvr_context *ctx)
{
u32 ctx_fw_addr = 0;
pvr_fw_object_get_fw_addr(ctx->fw_obj, &ctx_fw_addr);
return ctx_fw_addr;
}
void pvr_context_put(struct pvr_context *ctx);
int pvr_context_create(struct pvr_file *pvr_file, struct drm_pvr_ioctl_create_context_args *args);
int pvr_context_destroy(struct pvr_file *pvr_file, u32 handle);
void pvr_destroy_contexts_for_file(struct pvr_file *pvr_file);
void pvr_context_device_init(struct pvr_device *pvr_dev);
void pvr_context_device_fini(struct pvr_device *pvr_dev);
#endif