diff options
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a/fifo_gk20a.c')
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/fifo_gk20a.c | 110 |
1 files changed, 89 insertions, 21 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/fifo_gk20a.c b/drivers/gpu/nvgpu/gk20a/fifo_gk20a.c index 22dc1d60..c94fc536 100644 --- a/drivers/gpu/nvgpu/gk20a/fifo_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/fifo_gk20a.c | |||
@@ -53,6 +53,7 @@ | |||
53 | #include <nvgpu/hw/gk20a/hw_gr_gk20a.h> | 53 | #include <nvgpu/hw/gk20a/hw_gr_gk20a.h> |
54 | 54 | ||
55 | #define FECS_METHOD_WFI_RESTORE 0x80000 | 55 | #define FECS_METHOD_WFI_RESTORE 0x80000 |
56 | #define FECS_MAILBOX_0_ACK_RESTORE 0x4 | ||
56 | 57 | ||
57 | static int gk20a_fifo_update_runlist_locked(struct gk20a *g, u32 runlist_id, | 58 | static int gk20a_fifo_update_runlist_locked(struct gk20a *g, u32 runlist_id, |
58 | u32 chid, bool add, | 59 | u32 chid, bool add, |
@@ -3282,7 +3283,6 @@ static int gk20a_fifo_update_runlist_locked(struct gk20a *g, u32 runlist_id, | |||
3282 | u32 new_buf; | 3283 | u32 new_buf; |
3283 | struct channel_gk20a *ch = NULL; | 3284 | struct channel_gk20a *ch = NULL; |
3284 | struct tsg_gk20a *tsg = NULL; | 3285 | struct tsg_gk20a *tsg = NULL; |
3285 | u32 count = 0; | ||
3286 | u32 runlist_entry_words = f->runlist_entry_size / sizeof(u32); | 3286 | u32 runlist_entry_words = f->runlist_entry_size / sizeof(u32); |
3287 | 3287 | ||
3288 | runlist = &f->runlist_info[runlist_id]; | 3288 | runlist = &f->runlist_info[runlist_id]; |
@@ -3345,12 +3345,13 @@ static int gk20a_fifo_update_runlist_locked(struct gk20a *g, u32 runlist_id, | |||
3345 | ret = -E2BIG; | 3345 | ret = -E2BIG; |
3346 | goto clean_up; | 3346 | goto clean_up; |
3347 | } | 3347 | } |
3348 | count = (runlist_end - runlist_entry_base) / runlist_entry_words; | 3348 | runlist->count = (runlist_end - runlist_entry_base) / |
3349 | WARN_ON(count > f->num_runlist_entries); | 3349 | runlist_entry_words; |
3350 | WARN_ON(runlist->count > f->num_runlist_entries); | ||
3350 | } else /* suspend to remove all channels */ | 3351 | } else /* suspend to remove all channels */ |
3351 | count = 0; | 3352 | runlist->count = 0; |
3352 | 3353 | ||
3353 | g->ops.fifo.runlist_hw_submit(g, runlist_id, count, new_buf); | 3354 | g->ops.fifo.runlist_hw_submit(g, runlist_id, runlist->count, new_buf); |
3354 | 3355 | ||
3355 | if (wait_for_finish) { | 3356 | if (wait_for_finish) { |
3356 | ret = g->ops.fifo.runlist_wait_pending(g, runlist_id); | 3357 | ret = g->ops.fifo.runlist_wait_pending(g, runlist_id); |
@@ -3406,31 +3407,98 @@ end: | |||
3406 | return ret; | 3407 | return ret; |
3407 | } | 3408 | } |
3408 | 3409 | ||
3410 | /* trigger host preempt of GR pending load ctx if that ctx is not for ch */ | ||
3411 | static int __locked_fifo_reschedule_preempt_next(struct channel_gk20a *ch, | ||
3412 | bool wait_preempt) | ||
3413 | { | ||
3414 | struct gk20a *g = ch->g; | ||
3415 | struct fifo_runlist_info_gk20a *runlist = | ||
3416 | &g->fifo.runlist_info[ch->runlist_id]; | ||
3417 | int ret = 0; | ||
3418 | u32 gr_eng_id = 0; | ||
3419 | u32 engstat = 0, ctxstat = 0, fecsstat0 = 0, fecsstat1 = 0; | ||
3420 | s32 preempt_id = -1; | ||
3421 | u32 preempt_type = 0; | ||
3422 | |||
3423 | if (1 != gk20a_fifo_get_engine_ids( | ||
3424 | g, &gr_eng_id, 1, ENGINE_GR_GK20A)) | ||
3425 | return ret; | ||
3426 | if (!(runlist->eng_bitmask & (1 << gr_eng_id))) | ||
3427 | return ret; | ||
3428 | |||
3429 | if (wait_preempt && gk20a_readl(g, fifo_preempt_r()) & | ||
3430 | fifo_preempt_pending_true_f()) | ||
3431 | return ret; | ||
3432 | |||
3433 | fecsstat0 = gk20a_readl(g, gr_fecs_ctxsw_mailbox_r(0)); | ||
3434 | engstat = gk20a_readl(g, fifo_engine_status_r(gr_eng_id)); | ||
3435 | ctxstat = fifo_engine_status_ctx_status_v(engstat); | ||
3436 | if (ctxstat == fifo_engine_status_ctx_status_ctxsw_switch_v()) { | ||
3437 | /* host switching to next context, preempt that if needed */ | ||
3438 | preempt_id = fifo_engine_status_next_id_v(engstat); | ||
3439 | preempt_type = fifo_engine_status_next_id_type_v(engstat); | ||
3440 | } else | ||
3441 | return ret; | ||
3442 | if (preempt_id == ch->tsgid && preempt_type) | ||
3443 | return ret; | ||
3444 | fecsstat1 = gk20a_readl(g, gr_fecs_ctxsw_mailbox_r(0)); | ||
3445 | if (fecsstat0 != FECS_MAILBOX_0_ACK_RESTORE || | ||
3446 | fecsstat1 != FECS_MAILBOX_0_ACK_RESTORE) { | ||
3447 | /* preempt useless if FECS acked save and started restore */ | ||
3448 | return ret; | ||
3449 | } | ||
3450 | |||
3451 | gk20a_fifo_issue_preempt(g, preempt_id, preempt_type); | ||
3452 | #ifdef TRACEPOINTS_ENABLED | ||
3453 | trace_gk20a_reschedule_preempt_next(ch->chid, fecsstat0, engstat, | ||
3454 | fecsstat1, gk20a_readl(g, gr_fecs_ctxsw_mailbox_r(0)), | ||
3455 | gk20a_readl(g, fifo_preempt_r())); | ||
3456 | #endif | ||
3457 | if (wait_preempt) { | ||
3458 | g->ops.fifo.is_preempt_pending( | ||
3459 | g, preempt_id, preempt_type, PREEMPT_TIMEOUT_RC); | ||
3460 | } | ||
3461 | #ifdef TRACEPOINTS_ENABLED | ||
3462 | trace_gk20a_reschedule_preempted_next(ch->chid); | ||
3463 | #endif | ||
3464 | return ret; | ||
3465 | } | ||
3466 | |||
3467 | int gk20a_fifo_reschedule_runlist(struct channel_gk20a *ch, bool preempt_next) | ||
3468 | { | ||
3469 | return nvgpu_fifo_reschedule_runlist(ch, preempt_next, true); | ||
3470 | } | ||
3471 | |||
3409 | /* trigger host to expire current timeslice and reschedule runlist from front */ | 3472 | /* trigger host to expire current timeslice and reschedule runlist from front */ |
3410 | int gk20a_fifo_reschedule_runlist(struct gk20a *g, u32 runlist_id) | 3473 | int nvgpu_fifo_reschedule_runlist(struct channel_gk20a *ch, bool preempt_next, |
3474 | bool wait_preempt) | ||
3411 | { | 3475 | { |
3476 | struct gk20a *g = ch->g; | ||
3412 | struct fifo_runlist_info_gk20a *runlist; | 3477 | struct fifo_runlist_info_gk20a *runlist; |
3413 | u32 token = PMU_INVALID_MUTEX_OWNER_ID; | 3478 | u32 token = PMU_INVALID_MUTEX_OWNER_ID; |
3414 | u32 mutex_ret; | 3479 | u32 mutex_ret; |
3415 | int ret = 0; | 3480 | int ret = 0; |
3416 | 3481 | ||
3417 | runlist = &g->fifo.runlist_info[runlist_id]; | 3482 | runlist = &g->fifo.runlist_info[ch->runlist_id]; |
3418 | if (nvgpu_mutex_tryacquire(&runlist->runlist_lock)) { | 3483 | if (!nvgpu_mutex_tryacquire(&runlist->runlist_lock)) |
3419 | mutex_ret = nvgpu_pmu_mutex_acquire( | 3484 | return -EBUSY; |
3420 | &g->pmu, PMU_MUTEX_ID_FIFO, &token); | ||
3421 | 3485 | ||
3422 | gk20a_writel(g, fifo_runlist_r(), | 3486 | mutex_ret = nvgpu_pmu_mutex_acquire( |
3423 | gk20a_readl(g, fifo_runlist_r())); | 3487 | &g->pmu, PMU_MUTEX_ID_FIFO, &token); |
3424 | gk20a_fifo_runlist_wait_pending(g, runlist_id); | 3488 | |
3489 | g->ops.fifo.runlist_hw_submit( | ||
3490 | g, ch->runlist_id, runlist->count, runlist->cur_buffer); | ||
3491 | |||
3492 | if (preempt_next) | ||
3493 | __locked_fifo_reschedule_preempt_next(ch, wait_preempt); | ||
3494 | |||
3495 | gk20a_fifo_runlist_wait_pending(g, ch->runlist_id); | ||
3496 | |||
3497 | if (!mutex_ret) | ||
3498 | nvgpu_pmu_mutex_release( | ||
3499 | &g->pmu, PMU_MUTEX_ID_FIFO, &token); | ||
3500 | nvgpu_mutex_release(&runlist->runlist_lock); | ||
3425 | 3501 | ||
3426 | if (!mutex_ret) | ||
3427 | nvgpu_pmu_mutex_release( | ||
3428 | &g->pmu, PMU_MUTEX_ID_FIFO, &token); | ||
3429 | nvgpu_mutex_release(&runlist->runlist_lock); | ||
3430 | } else { | ||
3431 | /* someone else is writing fifo_runlist_r so not needed here */ | ||
3432 | ret = -EBUSY; | ||
3433 | } | ||
3434 | return ret; | 3502 | return ret; |
3435 | } | 3503 | } |
3436 | 3504 | ||