Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion drivers/gpu/drm/v3d/v3d_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,12 +150,24 @@ v3d_open(struct drm_device *dev, struct drm_file *file)
static void
v3d_postclose(struct drm_device *dev, struct drm_file *file)
{
struct v3d_dev *v3d = to_v3d_dev(dev);
struct v3d_file_priv *v3d_priv = file->driver_priv;
unsigned long irqflags;
enum v3d_queue q;

for (q = 0; q < V3D_MAX_QUEUES; q++)
for (q = 0; q < V3D_MAX_QUEUES; q++) {
struct v3d_queue_state *queue = &v3d->queue[q];
struct v3d_job *job = queue->active_job;

drm_sched_entity_destroy(&v3d_priv->sched_entity[q]);

if (job && job->base.entity == &v3d_priv->sched_entity[q]) {
spin_lock_irqsave(&queue->queue_lock, irqflags);
job->file_priv = NULL;
spin_unlock_irqrestore(&queue->queue_lock, irqflags);
}
}

v3d_perfmon_close_file(v3d_priv);
kfree(v3d_priv);
}
Expand Down
22 changes: 8 additions & 14 deletions drivers/gpu/drm/v3d/v3d_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ struct v3d_queue_state {

/* Stores the GPU stats for this queue in the global context. */
struct v3d_stats stats;

/* Currently active job for this queue */
struct v3d_job *active_job;
spinlock_t queue_lock;
};

/* Performance monitor object. The perform lifetime is controlled by userspace
Expand Down Expand Up @@ -165,18 +169,8 @@ struct v3d_dev {

struct work_struct overflow_mem_work;

struct v3d_bin_job *bin_job;
struct v3d_render_job *render_job;
struct v3d_tfu_job *tfu_job;
struct v3d_csd_job *csd_job;

struct v3d_queue_state queue[V3D_MAX_QUEUES];

/* Spinlock used to synchronize the overflow memory
* management against bin job submission.
*/
spinlock_t job_lock;

/* Used to track the active perfmon if any. */
struct v3d_perfmon *active_perfmon;

Expand Down Expand Up @@ -322,9 +316,9 @@ struct v3d_job {
struct v3d_perfmon *perfmon;

/* File descriptor of the process that submitted the job that could be used
* for collecting stats by process of GPU usage.
* to collect per-process information about the GPU.
*/
struct drm_file *file;
struct v3d_file_priv *file_priv;

/* Callback for the freeing of the job on refcount going to 0. */
void (*free)(struct kref *ref);
Expand Down Expand Up @@ -565,7 +559,7 @@ void v3d_get_stats(const struct v3d_stats *stats, u64 timestamp,

/* v3d_fence.c */
extern const struct dma_fence_ops v3d_fence_ops;
struct dma_fence *v3d_fence_create(struct v3d_dev *v3d, enum v3d_queue queue);
struct dma_fence *v3d_fence_create(struct v3d_dev *v3d, enum v3d_queue q);

/* v3d_gem.c */
int v3d_gem_init(struct drm_device *dev);
Expand Down Expand Up @@ -609,7 +603,7 @@ void v3d_timestamp_query_info_free(struct v3d_timestamp_query_info *query_info,
unsigned int count);
void v3d_performance_query_info_free(struct v3d_performance_query_info *query_info,
unsigned int count);
void v3d_job_update_stats(struct v3d_job *job, enum v3d_queue queue);
void v3d_job_update_stats(struct v3d_job *job, enum v3d_queue q);
int v3d_sched_init(struct v3d_dev *v3d);
void v3d_sched_fini(struct v3d_dev *v3d);

Expand Down
11 changes: 6 additions & 5 deletions drivers/gpu/drm/v3d/v3d_fence.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,20 @@

#include "v3d_drv.h"

struct dma_fence *v3d_fence_create(struct v3d_dev *v3d, enum v3d_queue queue)
struct dma_fence *v3d_fence_create(struct v3d_dev *v3d, enum v3d_queue q)
{
struct v3d_queue_state *queue = &v3d->queue[q];
struct v3d_fence *fence;

fence = kzalloc(sizeof(*fence), GFP_KERNEL);
if (!fence)
return ERR_PTR(-ENOMEM);

fence->dev = &v3d->drm;
fence->queue = queue;
fence->seqno = ++v3d->queue[queue].emit_seqno;
dma_fence_init(&fence->base, &v3d_fence_ops, &v3d->job_lock,
v3d->queue[queue].fence_context, fence->seqno);
fence->queue = q;
fence->seqno = ++queue->emit_seqno;
dma_fence_init(&fence->base, &v3d_fence_ops, &queue->queue_lock,
queue->fence_context, fence->seqno);

return &fence->base;
}
Expand Down
10 changes: 5 additions & 5 deletions drivers/gpu/drm/v3d/v3d_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -272,10 +272,11 @@ v3d_gem_init(struct drm_device *dev)
queue->fence_context = dma_fence_context_alloc(1);
memset(&queue->stats, 0, sizeof(queue->stats));
seqcount_init(&queue->stats.lock);

spin_lock_init(&queue->queue_lock);
}

spin_lock_init(&v3d->mm_lock);
spin_lock_init(&v3d->job_lock);
ret = drmm_mutex_init(dev, &v3d->bo_lock);
if (ret)
return ret;
Expand Down Expand Up @@ -327,17 +328,16 @@ void
v3d_gem_destroy(struct drm_device *dev)
{
struct v3d_dev *v3d = to_v3d_dev(dev);
enum v3d_queue q;

v3d_sched_fini(v3d);
v3d_gemfs_fini(v3d);

/* Waiting for jobs to finish would need to be done before
* unregistering V3D.
*/
WARN_ON(v3d->bin_job);
WARN_ON(v3d->render_job);
WARN_ON(v3d->tfu_job);
WARN_ON(v3d->csd_job);
for (q = 0; q < V3D_MAX_QUEUES; q++)
WARN_ON(v3d->queue[q].active_job);

drm_mm_takedown(&v3d->mm);

Expand Down
68 changes: 27 additions & 41 deletions drivers/gpu/drm/v3d/v3d_irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ v3d_overflow_mem_work(struct work_struct *work)
container_of(work, struct v3d_dev, overflow_mem_work);
struct drm_device *dev = &v3d->drm;
struct v3d_bo *bo = v3d_bo_create(dev, NULL /* XXX: GMP */, 256 * 1024);
struct v3d_queue_state *queue = &v3d->queue[V3D_BIN];
struct v3d_bin_job *bin_job;
struct drm_gem_object *obj;
unsigned long irqflags;

Expand All @@ -60,15 +62,17 @@ v3d_overflow_mem_work(struct work_struct *work)
* bin job got scheduled, that's fine. We'll just give them
* some binner pool anyway.
*/
spin_lock_irqsave(&v3d->job_lock, irqflags);
if (!v3d->bin_job) {
spin_unlock_irqrestore(&v3d->job_lock, irqflags);
spin_lock_irqsave(&queue->queue_lock, irqflags);
bin_job = (struct v3d_bin_job *)queue->active_job;

if (!bin_job) {
spin_unlock_irqrestore(&queue->queue_lock, irqflags);
goto out;
}

drm_gem_object_get(obj);
list_add_tail(&bo->unref_head, &v3d->bin_job->render->unref_list);
spin_unlock_irqrestore(&v3d->job_lock, irqflags);
list_add_tail(&bo->unref_head, &bin_job->render->unref_list);
spin_unlock_irqrestore(&queue->queue_lock, irqflags);

v3d_mmu_flush_all(v3d);

Expand All @@ -79,6 +83,20 @@ v3d_overflow_mem_work(struct work_struct *work)
drm_gem_object_put(obj);
}

static void
v3d_irq_signal_fence(struct v3d_dev *v3d, enum v3d_queue q,
void (*trace_irq)(struct drm_device *, uint64_t))
{
struct v3d_queue_state *queue = &v3d->queue[q];
struct v3d_fence *fence = to_v3d_fence(queue->active_job->irq_fence);

v3d_job_update_stats(queue->active_job, q);
trace_irq(&v3d->drm, fence->seqno);

queue->active_job = NULL;
dma_fence_signal(&fence->base);
}

static irqreturn_t
v3d_irq(int irq, void *arg)
{
Expand All @@ -102,41 +120,17 @@ v3d_irq(int irq, void *arg)
}

if (intsts & V3D_INT_FLDONE) {
struct v3d_fence *fence =
to_v3d_fence(v3d->bin_job->base.irq_fence);

v3d_job_update_stats(&v3d->bin_job->base, V3D_BIN);
trace_v3d_bcl_irq(&v3d->drm, fence->seqno);

v3d->bin_job = NULL;
dma_fence_signal(&fence->base);

v3d_irq_signal_fence(v3d, V3D_BIN, trace_v3d_bcl_irq);
status = IRQ_HANDLED;
}

if (intsts & V3D_INT_FRDONE) {
struct v3d_fence *fence =
to_v3d_fence(v3d->render_job->base.irq_fence);

v3d_job_update_stats(&v3d->render_job->base, V3D_RENDER);
trace_v3d_rcl_irq(&v3d->drm, fence->seqno);

v3d->render_job = NULL;
dma_fence_signal(&fence->base);

v3d_irq_signal_fence(v3d, V3D_RENDER, trace_v3d_rcl_irq);
status = IRQ_HANDLED;
}

if (intsts & V3D_INT_CSDDONE(v3d->ver)) {
struct v3d_fence *fence =
to_v3d_fence(v3d->csd_job->base.irq_fence);

v3d_job_update_stats(&v3d->csd_job->base, V3D_CSD);
trace_v3d_csd_irq(&v3d->drm, fence->seqno);

v3d->csd_job = NULL;
dma_fence_signal(&fence->base);

v3d_irq_signal_fence(v3d, V3D_CSD, trace_v3d_csd_irq);
status = IRQ_HANDLED;
}

Expand Down Expand Up @@ -168,15 +162,7 @@ v3d_hub_irq(int irq, void *arg)
V3D_WRITE(V3D_HUB_INT_CLR, intsts);

if (intsts & V3D_HUB_INT_TFUC) {
struct v3d_fence *fence =
to_v3d_fence(v3d->tfu_job->base.irq_fence);

v3d_job_update_stats(&v3d->tfu_job->base, V3D_TFU);
trace_v3d_tfu_irq(&v3d->drm, fence->seqno);

v3d->tfu_job = NULL;
dma_fence_signal(&fence->base);

v3d_irq_signal_fence(v3d, V3D_TFU, trace_v3d_tfu_irq);
status = IRQ_HANDLED;
}

Expand Down
45 changes: 23 additions & 22 deletions drivers/gpu/drm/v3d/v3d_sched.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ static void
v3d_job_start_stats(struct v3d_job *job, enum v3d_queue queue)
{
struct v3d_dev *v3d = job->v3d;
struct v3d_file_priv *file = job->file->driver_priv;
struct v3d_file_priv *file = job->file_priv;
struct v3d_stats *global_stats = &v3d->queue[queue].stats;
struct v3d_stats *local_stats = &file->stats[queue];
u64 now = local_clock();
Expand Down Expand Up @@ -194,11 +194,11 @@ v3d_stats_update(struct v3d_stats *stats, u64 now)
}

void
v3d_job_update_stats(struct v3d_job *job, enum v3d_queue queue)
v3d_job_update_stats(struct v3d_job *job, enum v3d_queue q)
{
struct v3d_dev *v3d = job->v3d;
struct v3d_file_priv *file = job->file->driver_priv;
struct v3d_stats *global_stats = &v3d->queue[queue].stats;
struct v3d_queue_state *queue = &v3d->queue[q];
struct v3d_stats *global_stats = &queue->stats;
u64 now = local_clock();
unsigned long flags;

Expand All @@ -209,10 +209,10 @@ v3d_job_update_stats(struct v3d_job *job, enum v3d_queue queue)
preempt_disable();

/* Don't update the local stats if the file context has already closed */
if (file)
v3d_stats_update(&file->stats[queue], now);
else
drm_dbg(&v3d->drm, "The file descriptor was closed before job completion\n");
spin_lock(&queue->queue_lock);
if (job->file_priv)
v3d_stats_update(&job->file_priv->stats[q], now);
spin_unlock(&queue->queue_lock);

v3d_stats_update(global_stats, now);

Expand All @@ -226,27 +226,28 @@ static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job)
{
struct v3d_bin_job *job = to_bin_job(sched_job);
struct v3d_dev *v3d = job->base.v3d;
struct v3d_queue_state *queue = &v3d->queue[V3D_BIN];
struct drm_device *dev = &v3d->drm;
struct dma_fence *fence;
unsigned long irqflags;

if (unlikely(job->base.base.s_fence->finished.error)) {
spin_lock_irqsave(&v3d->job_lock, irqflags);
v3d->bin_job = NULL;
spin_unlock_irqrestore(&v3d->job_lock, irqflags);
spin_lock_irqsave(&queue->queue_lock, irqflags);
queue->active_job = NULL;
spin_unlock_irqrestore(&queue->queue_lock, irqflags);
return NULL;
}

/* Lock required around bin_job update vs
* v3d_overflow_mem_work().
*/
spin_lock_irqsave(&v3d->job_lock, irqflags);
v3d->bin_job = job;
spin_lock_irqsave(&queue->queue_lock, irqflags);
queue->active_job = &job->base;
/* Clear out the overflow allocation, so we don't
* reuse the overflow attached to a previous job.
*/
V3D_CORE_WRITE(0, V3D_PTB_BPOS, 0);
spin_unlock_irqrestore(&v3d->job_lock, irqflags);
spin_unlock_irqrestore(&queue->queue_lock, irqflags);

v3d_invalidate_caches(v3d);

Expand Down Expand Up @@ -290,11 +291,11 @@ static struct dma_fence *v3d_render_job_run(struct drm_sched_job *sched_job)
struct dma_fence *fence;

if (unlikely(job->base.base.s_fence->finished.error)) {
v3d->render_job = NULL;
v3d->queue[V3D_RENDER].active_job = NULL;
return NULL;
}

v3d->render_job = job;
v3d->queue[V3D_RENDER].active_job = &job->base;

/* Can we avoid this flush? We need to be careful of
* scheduling, though -- imagine job0 rendering to texture and
Expand Down Expand Up @@ -338,11 +339,11 @@ v3d_tfu_job_run(struct drm_sched_job *sched_job)
struct dma_fence *fence;

if (unlikely(job->base.base.s_fence->finished.error)) {
v3d->tfu_job = NULL;
v3d->queue[V3D_TFU].active_job = NULL;
return NULL;
}

v3d->tfu_job = job;
v3d->queue[V3D_TFU].active_job = &job->base;

fence = v3d_fence_create(v3d, V3D_TFU);
if (IS_ERR(fence))
Expand Down Expand Up @@ -386,11 +387,11 @@ v3d_csd_job_run(struct drm_sched_job *sched_job)
int i, csd_cfg0_reg;

if (unlikely(job->base.base.s_fence->finished.error)) {
v3d->csd_job = NULL;
v3d->queue[V3D_CSD].active_job = NULL;
return NULL;
}

v3d->csd_job = job;
v3d->queue[V3D_CSD].active_job = &job->base;

v3d_invalidate_caches(v3d);

Expand Down Expand Up @@ -574,7 +575,7 @@ static void
v3d_reset_performance_queries(struct v3d_cpu_job *job)
{
struct v3d_performance_query_info *performance_query = &job->performance_query;
struct v3d_file_priv *v3d_priv = job->base.file->driver_priv;
struct v3d_file_priv *v3d_priv = job->base.file_priv;
struct v3d_dev *v3d = job->base.v3d;
struct v3d_perfmon *perfmon;

Expand Down Expand Up @@ -604,7 +605,7 @@ v3d_write_performance_query_result(struct v3d_cpu_job *job, void *data,
{
struct v3d_performance_query_info *performance_query =
&job->performance_query;
struct v3d_file_priv *v3d_priv = job->base.file->driver_priv;
struct v3d_file_priv *v3d_priv = job->base.file_priv;
struct v3d_performance_query *perf_query =
&performance_query->queries[query];
struct v3d_dev *v3d = job->base.v3d;
Expand Down
Loading
Loading