From patchwork Mon Feb 1 08:56:45 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Wilson X-Patchwork-Id: 12058473 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 61B47C433DB for ; Mon, 1 Feb 2021 08:58:11 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 067B164E3F for ; Mon, 1 Feb 2021 08:58:10 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 067B164E3F Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=chris-wilson.co.uk Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=intel-gfx-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id F179A6E4D2; Mon, 1 Feb 2021 08:57:42 +0000 (UTC) Received: from fireflyinternet.com (unknown [77.68.26.236]) by gabe.freedesktop.org (Postfix) with ESMTPS id 2E91B6E4B6 for ; Mon, 1 Feb 2021 08:57:34 +0000 (UTC) X-Default-Received-SPF: pass (skip=forwardok (res=PASS)) x-ip-name=78.156.65.138; Received: from build.alporthouse.com (unverified [78.156.65.138]) by fireflyinternet.com (Firefly Internet (M1)) with ESMTP id 23757740-1500050 for multiple; Mon, 01 Feb 2021 08:57:20 +0000 From: Chris Wilson To: intel-gfx@lists.freedesktop.org Date: Mon, 1 Feb 2021 08:56:45 +0000 Message-Id: <20210201085715.27435-27-chris@chris-wilson.co.uk> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210201085715.27435-1-chris@chris-wilson.co.uk> References: <20210201085715.27435-1-chris@chris-wilson.co.uk> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH 27/57] drm/i915: Show execlists queues when dumping state X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Chris Wilson Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" Move the scheduler pretty printer from out of the execlists register state to and push it to the schduler. v2: It's not common to all, so shove it out of intel_engine_cs and split it between scheduler front/back ends Signed-off-by: Chris Wilson Reviewed-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/gt/intel_engine_cs.c | 233 +----------------- .../drm/i915/gt/intel_execlists_submission.c | 174 ++++++++----- drivers/gpu/drm/i915/i915_request.c | 6 + drivers/gpu/drm/i915/i915_scheduler.c | 180 ++++++++++++++ drivers/gpu/drm/i915/i915_scheduler.h | 8 + drivers/gpu/drm/i915/i915_scheduler_types.h | 9 + 6 files changed, 331 insertions(+), 279 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index 5751a529b2df..9ff597ef5aca 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -1277,49 +1277,6 @@ bool intel_engine_can_store_dword(struct intel_engine_cs *engine) } } -static struct intel_timeline *get_timeline(const struct i915_request *rq) -{ - struct intel_timeline *tl; - - /* - * Even though we are holding the engine->active.lock here, there - * is no control over the submission queue per-se and we are - * inspecting the active state at a random point in time, with an - * unknown queue. Play safe and make sure the timeline remains valid. - * (Only being used for pretty printing, one extra kref shouldn't - * cause a camel stampede!) - */ - rcu_read_lock(); - tl = rcu_dereference(rq->timeline); - if (!kref_get_unless_zero(&tl->kref)) - tl = NULL; - rcu_read_unlock(); - - return tl; -} - -static int print_ring(char *buf, int sz, struct i915_request *rq) -{ - int len = 0; - - if (!i915_request_signaled(rq)) { - struct intel_timeline *tl = get_timeline(rq); - - len = scnprintf(buf, sz, - "ring:{start:%08x, hwsp:%08x, seqno:%08x, runtime:%llums}, ", - i915_ggtt_offset(rq->ring->vma), - tl ? tl->hwsp_offset : 0, - hwsp_seqno(rq), - DIV_ROUND_CLOSEST_ULL(intel_context_get_total_runtime_ns(rq->context), - 1000 * 1000)); - - if (tl) - intel_timeline_put(tl); - } - - return len; -} - static void hexdump(struct drm_printer *m, const void *buf, size_t len) { const size_t rowsize = 8 * sizeof(u32); @@ -1349,27 +1306,15 @@ static void hexdump(struct drm_printer *m, const void *buf, size_t len) } } -static const char *repr_timer(const struct timer_list *t) -{ - if (!READ_ONCE(t->expires)) - return "inactive"; - - if (timer_pending(t)) - return "active"; - - return "expired"; -} - static void intel_engine_print_registers(struct intel_engine_cs *engine, struct drm_printer *m) { - struct drm_i915_private *dev_priv = engine->i915; - struct intel_engine_execlists * const execlists = &engine->execlists; + struct drm_i915_private *i915 = engine->i915; u64 addr; - if (engine->id == RENDER_CLASS && IS_GEN_RANGE(dev_priv, 4, 7)) + if (engine->id == RENDER_CLASS && IS_GEN_RANGE(i915, 4, 7)) drm_printf(m, "\tCCID: 0x%08x\n", ENGINE_READ(engine, CCID)); - if (HAS_EXECLISTS(dev_priv)) { + if (HAS_EXECLISTS(i915)) { drm_printf(m, "\tEL_STAT_HI: 0x%08x\n", ENGINE_READ(engine, RING_EXECLIST_STATUS_HI)); drm_printf(m, "\tEL_STAT_LO: 0x%08x\n", @@ -1390,7 +1335,7 @@ static void intel_engine_print_registers(struct intel_engine_cs *engine, ENGINE_READ(engine, RING_MI_MODE) & (MODE_IDLE) ? " [idle]" : ""); } - if (INTEL_GEN(dev_priv) >= 6) { + if (INTEL_GEN(i915) >= 6) { drm_printf(m, "\tRING_IMR: 0x%08x\n", ENGINE_READ(engine, RING_IMR)); drm_printf(m, "\tRING_ESR: 0x%08x\n", @@ -1407,15 +1352,15 @@ static void intel_engine_print_registers(struct intel_engine_cs *engine, addr = intel_engine_get_last_batch_head(engine); drm_printf(m, "\tBBADDR: 0x%08x_%08x\n", upper_32_bits(addr), lower_32_bits(addr)); - if (INTEL_GEN(dev_priv) >= 8) + if (INTEL_GEN(i915) >= 8) addr = ENGINE_READ64(engine, RING_DMA_FADD, RING_DMA_FADD_UDW); - else if (INTEL_GEN(dev_priv) >= 4) + else if (INTEL_GEN(i915) >= 4) addr = ENGINE_READ(engine, RING_DMA_FADD); else addr = ENGINE_READ(engine, DMA_FADD_I8XX); drm_printf(m, "\tDMA_FADDR: 0x%08x_%08x\n", upper_32_bits(addr), lower_32_bits(addr)); - if (INTEL_GEN(dev_priv) >= 4) { + if (INTEL_GEN(i915) >= 4) { drm_printf(m, "\tIPEIR: 0x%08x\n", ENGINE_READ(engine, RING_IPEIR)); drm_printf(m, "\tIPEHR: 0x%08x\n", @@ -1424,130 +1369,6 @@ static void intel_engine_print_registers(struct intel_engine_cs *engine, drm_printf(m, "\tIPEIR: 0x%08x\n", ENGINE_READ(engine, IPEIR)); drm_printf(m, "\tIPEHR: 0x%08x\n", ENGINE_READ(engine, IPEHR)); } - - if (intel_engine_uses_guc(engine)) { - /* nothing to print yet */ - } else if (HAS_EXECLISTS(dev_priv)) { - struct i915_sched *se = intel_engine_get_scheduler(engine); - struct i915_request * const *port, *rq; - const u32 *hws = - &engine->status_page.addr[I915_HWS_CSB_BUF0_INDEX]; - const u8 num_entries = execlists->csb_size; - unsigned int idx; - u8 read, write; - - drm_printf(m, "\tExeclist tasklet queued? %s (%s), preempt? %s, timeslice? %s\n", - yesno(test_bit(TASKLET_STATE_SCHED, - &se->tasklet.state)), - enableddisabled(!atomic_read(&se->tasklet.count)), - repr_timer(&engine->execlists.preempt), - repr_timer(&engine->execlists.timer)); - - read = execlists->csb_head; - write = READ_ONCE(*execlists->csb_write); - - drm_printf(m, "\tExeclist status: 0x%08x %08x; CSB read:%d, write:%d, entries:%d\n", - ENGINE_READ(engine, RING_EXECLIST_STATUS_LO), - ENGINE_READ(engine, RING_EXECLIST_STATUS_HI), - read, write, num_entries); - - if (read >= num_entries) - read = 0; - if (write >= num_entries) - write = 0; - if (read > write) - write += num_entries; - while (read < write) { - idx = ++read % num_entries; - drm_printf(m, "\tExeclist CSB[%d]: 0x%08x, context: %d\n", - idx, hws[idx * 2], hws[idx * 2 + 1]); - } - - i915_sched_lock_bh(se); - rcu_read_lock(); - for (port = execlists->active; (rq = *port); port++) { - char hdr[160]; - int len; - - len = scnprintf(hdr, sizeof(hdr), - "\t\tActive[%d]: ccid:%08x%s%s, ", - (int)(port - execlists->active), - rq->context->lrc.ccid, - intel_context_is_closed(rq->context) ? "!" : "", - intel_context_is_banned(rq->context) ? "*" : ""); - len += print_ring(hdr + len, sizeof(hdr) - len, rq); - scnprintf(hdr + len, sizeof(hdr) - len, "rq: "); - i915_request_show(m, rq, hdr, 0); - } - for (port = execlists->pending; (rq = *port); port++) { - char hdr[160]; - int len; - - len = scnprintf(hdr, sizeof(hdr), - "\t\tPending[%d]: ccid:%08x%s%s, ", - (int)(port - execlists->pending), - rq->context->lrc.ccid, - intel_context_is_closed(rq->context) ? "!" : "", - intel_context_is_banned(rq->context) ? "*" : ""); - len += print_ring(hdr + len, sizeof(hdr) - len, rq); - scnprintf(hdr + len, sizeof(hdr) - len, "rq: "); - i915_request_show(m, rq, hdr, 0); - } - rcu_read_unlock(); - i915_sched_unlock_bh(se); - } else if (INTEL_GEN(dev_priv) > 6) { - drm_printf(m, "\tPP_DIR_BASE: 0x%08x\n", - ENGINE_READ(engine, RING_PP_DIR_BASE)); - drm_printf(m, "\tPP_DIR_BASE_READ: 0x%08x\n", - ENGINE_READ(engine, RING_PP_DIR_BASE_READ)); - drm_printf(m, "\tPP_DIR_DCLV: 0x%08x\n", - ENGINE_READ(engine, RING_PP_DIR_DCLV)); - } -} - -static void -print_request_ring(struct drm_printer *m, const struct i915_request *rq) -{ - void *ring; - int size; - - drm_printf(m, - "[head %04x, postfix %04x, tail %04x, batch 0x%08x_%08x]:\n", - rq->head, rq->postfix, rq->tail, - rq->batch ? upper_32_bits(rq->batch->node.start) : ~0u, - rq->batch ? lower_32_bits(rq->batch->node.start) : ~0u); - - size = rq->tail - rq->head; - if (rq->tail < rq->head) - size += rq->ring->size; - - ring = kmalloc(size, GFP_ATOMIC); - if (ring) { - const void *vaddr = rq->ring->vaddr; - unsigned int head = rq->head; - unsigned int len = 0; - - if (rq->tail < head) { - len = rq->ring->size - head; - memcpy(ring, vaddr + head, len); - head = 0; - } - memcpy(ring + len, vaddr + head, size - len); - - hexdump(m, ring, size); - kfree(ring); - } -} - -static unsigned long list_count(struct list_head *list) -{ - struct list_head *pos; - unsigned long count = 0; - - list_for_each(pos, list) - count++; - - return count; } static unsigned long read_ul(void *p, size_t x) @@ -1590,10 +1411,8 @@ void intel_engine_dump(struct intel_engine_cs *engine, const char *header, ...) { struct i915_gpu_error * const error = &engine->i915->gpu_error; - struct i915_sched *se = intel_engine_get_scheduler(engine); const struct i915_request *rq; intel_wakeref_t wakeref; - unsigned long flags; ktime_t dummy; if (header) { @@ -1632,41 +1451,9 @@ void intel_engine_dump(struct intel_engine_cs *engine, drm_printf(m, "\tRequests:\n"); - rcu_read_lock(); - spin_lock_irqsave(&se->lock, flags); - rq = se->active_request(se); - if (rq) { - struct intel_timeline *tl = get_timeline(rq); + i915_sched_show(m, intel_engine_get_scheduler(engine), + i915_request_show, 8); - i915_request_show(m, rq, "\t\tactive ", 0); - - drm_printf(m, "\t\tring->start: 0x%08x\n", - i915_ggtt_offset(rq->ring->vma)); - drm_printf(m, "\t\tring->head: 0x%08x\n", - rq->ring->head); - drm_printf(m, "\t\tring->tail: 0x%08x\n", - rq->ring->tail); - drm_printf(m, "\t\tring->emit: 0x%08x\n", - rq->ring->emit); - drm_printf(m, "\t\tring->space: 0x%08x\n", - rq->ring->space); - - if (tl) { - drm_printf(m, "\t\tring->hwsp: 0x%08x\n", - tl->hwsp_offset); - intel_timeline_put(tl); - } - - print_request_ring(m, rq); - - if (rq->context->lrc_reg_state) { - drm_printf(m, "Logical Ring Context:\n"); - hexdump(m, rq->context->lrc_reg_state, PAGE_SIZE); - } - } - drm_printf(m, "\tOn hold?: %lu\n", list_count(&se->hold)); - spin_unlock_irqrestore(&se->lock, flags); - rcu_read_unlock(); drm_printf(m, "\tMMIO base: 0x%08x\n", engine->mmio_base); wakeref = intel_runtime_pm_get_if_in_use(engine->uncore->rpm); @@ -1677,8 +1464,6 @@ void intel_engine_dump(struct intel_engine_cs *engine, drm_printf(m, "\tDevice is asleep; skipping register dump\n"); } - intel_execlists_show_requests(engine, m, i915_request_show, 8); - drm_printf(m, "HWSP:\n"); hexdump(m, engine->status_page.addr, PAGE_SIZE); diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c index 8b848adb65b7..b1007e560527 100644 --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c @@ -198,6 +198,14 @@ struct virtual_engine { struct intel_engine_cs *siblings[]; }; +static void execlists_show(struct drm_printer *m, + struct i915_sched *se, + void (*show_request)(struct drm_printer *m, + const struct i915_request *rq, + const char *prefix, + int indent), + unsigned int max); + static struct virtual_engine *to_virtual_engine(struct intel_engine_cs *engine) { GEM_BUG_ON(!intel_engine_is_virtual(engine)); @@ -2971,6 +2979,7 @@ int intel_execlists_submission_setup(struct intel_engine_cs *engine) engine->sched.active_request = execlists_active_request; engine->sched.is_executing = execlists_is_executing; + engine->sched.show = execlists_show; tasklet_setup(&engine->sched.tasklet, execlists_submission_tasklet); timer_setup(&engine->execlists.timer, execlists_timeslice, 0); timer_setup(&engine->execlists.preempt, execlists_preempt, 0); @@ -3581,68 +3590,65 @@ int intel_virtual_engine_attach_bond(struct intel_engine_cs *engine, return 0; } -void intel_execlists_show_requests(struct intel_engine_cs *engine, - struct drm_printer *m, - void (*show_request)(struct drm_printer *m, - const struct i915_request *rq, - const char *prefix, - int indent), - unsigned int max) +static const char *repr_timer(const struct timer_list *t) { - const struct intel_engine_execlists *execlists = &engine->execlists; - struct i915_sched *se = intel_engine_get_scheduler(engine); + if (!READ_ONCE(t->expires)) + return "inactive"; + + if (timer_pending(t)) + return "active"; + + return "expired"; +} + +static int print_ring(char *buf, int sz, struct i915_request *rq) +{ + int len = 0; + + rcu_read_lock(); + if (!i915_request_signaled(rq)) { + struct intel_timeline *tl = rcu_dereference(rq->timeline); + + len = scnprintf(buf, sz, + "ring:{start:%08x, hwsp:%08x, seqno:%08x, runtime:%llums}, ", + i915_ggtt_offset(rq->ring->vma), + tl ? tl->hwsp_offset : 0, + hwsp_seqno(rq), + DIV_ROUND_CLOSEST_ULL(intel_context_get_total_runtime_ns(rq->context), + 1000 * 1000)); + } + rcu_read_unlock(); + + return len; +} + +static void execlists_show(struct drm_printer *m, + struct i915_sched *se, + void (*show_request)(struct drm_printer *m, + const struct i915_request *rq, + const char *prefix, + int indent), + unsigned int max) +{ + const struct intel_engine_cs *engine = + container_of(se, typeof(*engine), sched); + const struct intel_engine_execlists *el = &engine->execlists; + const u64 *hws = el->csb_status; + const u8 num_entries = el->csb_size; + struct i915_request * const *port; struct i915_request *rq, *last; - unsigned long flags; + intel_wakeref_t wakeref; unsigned int count; struct rb_node *rb; + unsigned int idx; + u8 read, write; - spin_lock_irqsave(&se->lock, flags); + wakeref = intel_runtime_pm_get(engine->uncore->rpm); + rcu_read_lock(); last = NULL; count = 0; - list_for_each_entry(rq, &se->requests, sched.link) { - if (count++ < max - 1) - show_request(m, rq, "\t\t", 0); - else - last = rq; - } - if (last) { - if (count > max) { - drm_printf(m, - "\t\t...skipping %d executing requests...\n", - count - max); - } - show_request(m, last, "\t\t", 0); - } - - if (execlists->queue_priority_hint != INT_MIN) - drm_printf(m, "\t\tQueue priority hint: %d\n", - READ_ONCE(execlists->queue_priority_hint)); - - last = NULL; - count = 0; - for (rb = rb_first_cached(&se->queue); rb; rb = rb_next(rb)) { - struct i915_priolist *p = rb_entry(rb, typeof(*p), node); - - priolist_for_each_request(rq, p) { - if (count++ < max - 1) - show_request(m, rq, "\t\t", 0); - else - last = rq; - } - } - if (last) { - if (count > max) { - drm_printf(m, - "\t\t...skipping %d queued requests...\n", - count - max); - } - show_request(m, last, "\t\t", 0); - } - - last = NULL; - count = 0; - for (rb = rb_first_cached(&execlists->virtual); rb; rb = rb_next(rb)) { + for (rb = rb_first_cached(&el->virtual); rb; rb = rb_next(rb)) { struct virtual_engine *ve = rb_entry(rb, typeof(*ve), nodes[engine->id].rb); struct i915_request *rq = READ_ONCE(ve->request); @@ -3663,7 +3669,65 @@ void intel_execlists_show_requests(struct intel_engine_cs *engine, show_request(m, last, "\t\t", 0); } - spin_unlock_irqrestore(&se->lock, flags); + drm_printf(m, "\tExeclists preempt? %s, timeslice? %s\n", + repr_timer(&el->preempt), + repr_timer(&el->timer)); + + read = el->csb_head; + write = READ_ONCE(*el->csb_write); + + drm_printf(m, "\tExeclist status: 0x%08x %08x; CSB read:%d, write:%d, entries:%d\n", + ENGINE_READ(engine, RING_EXECLIST_STATUS_LO), + ENGINE_READ(engine, RING_EXECLIST_STATUS_HI), + read, write, num_entries); + + if (read >= num_entries) + read = 0; + if (write >= num_entries) + write = 0; + if (read > write) + write += num_entries; + while (read < write) { + idx = ++read % num_entries; + drm_printf(m, "\tExeclist CSB[%d]: 0x%08x, context: %d\n", + idx, + lower_32_bits(hws[idx]), + upper_32_bits(hws[idx])); + } + + i915_sched_lock_bh(se); + for (port = el->active; (rq = *port); port++) { + char hdr[160]; + int len; + + len = scnprintf(hdr, sizeof(hdr), + "\t\tActive[%d]: ccid:%08x%s%s, ", + (int)(port - el->active), + rq->context->lrc.ccid, + intel_context_is_closed(rq->context) ? "!" : "", + intel_context_is_banned(rq->context) ? "*" : ""); + len += print_ring(hdr + len, sizeof(hdr) - len, rq); + scnprintf(hdr + len, sizeof(hdr) - len, "rq: "); + i915_request_show(m, rq, hdr, 0); + } + for (port = el->pending; (rq = *port); port++) { + char hdr[160]; + int len; + + len = scnprintf(hdr, sizeof(hdr), + "\t\tPending[%d]: ccid:%08x%s%s, ", + (int)(port - el->pending), + rq->context->lrc.ccid, + intel_context_is_closed(rq->context) ? "!" : "", + intel_context_is_banned(rq->context) ? "*" : ""); + len += print_ring(hdr + len, sizeof(hdr) - len, rq); + scnprintf(hdr + len, sizeof(hdr) - len, "rq: "); + i915_request_show(m, rq, hdr, 0); + } + i915_sched_unlock_bh(se); + + rcu_read_unlock(); + intel_runtime_pm_put(engine->uncore->rpm, wakeref); } #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index 792dd0bbea3b..459f727b03cd 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -1827,6 +1827,9 @@ static char queue_status(const struct i915_request *rq) if (i915_request_is_active(rq)) return 'E'; + if (i915_request_on_hold(rq)) + return 'S'; + if (i915_request_is_ready(rq)) return intel_engine_is_virtual(rq->engine) ? 'V' : 'R'; @@ -1895,6 +1898,9 @@ void i915_request_show(struct drm_printer *m, * - a completed request may still be regarded as executing, its * status may not be updated until it is retired and removed * from the lists + * + * S [Suspended] + * - the request has been temporarily suspended from execution */ x = print_sched_attr(&rq->sched.attr, buf, x, sizeof(buf)); diff --git a/drivers/gpu/drm/i915/i915_scheduler.c b/drivers/gpu/drm/i915/i915_scheduler.c index cb27bcb7a1f6..af3a12d6f6d2 100644 --- a/drivers/gpu/drm/i915/i915_scheduler.c +++ b/drivers/gpu/drm/i915/i915_scheduler.c @@ -1124,6 +1124,186 @@ void i915_request_show_with_schedule(struct drm_printer *m, rcu_read_unlock(); } +static unsigned long list_count(struct list_head *list) +{ + struct list_head *pos; + unsigned long count = 0; + + list_for_each(pos, list) + count++; + + return count; +} + +static void hexdump(struct drm_printer *m, const void *buf, size_t len) +{ + const size_t rowsize = 8 * sizeof(u32); + const void *prev = NULL; + bool skip = false; + size_t pos; + + for (pos = 0; pos < len; pos += rowsize) { + char line[128]; + + if (prev && !memcmp(prev, buf + pos, rowsize)) { + if (!skip) { + drm_printf(m, "*\n"); + skip = true; + } + continue; + } + + WARN_ON_ONCE(hex_dump_to_buffer(buf + pos, len - pos, + rowsize, sizeof(u32), + line, sizeof(line), + false) >= sizeof(line)); + drm_printf(m, "[%04zx] %s\n", pos, line); + + prev = buf + pos; + skip = false; + } +} + +static void +print_request_ring(struct drm_printer *m, const struct i915_request *rq) +{ + void *ring; + int size; + + drm_printf(m, + "[head %04x, postfix %04x, tail %04x, batch 0x%08x_%08x]:\n", + rq->head, rq->postfix, rq->tail, + rq->batch ? upper_32_bits(rq->batch->node.start) : ~0u, + rq->batch ? lower_32_bits(rq->batch->node.start) : ~0u); + + size = rq->tail - rq->head; + if (rq->tail < rq->head) + size += rq->ring->size; + + ring = kmalloc(size, GFP_ATOMIC); + if (ring) { + const void *vaddr = rq->ring->vaddr; + unsigned int head = rq->head; + unsigned int len = 0; + + if (rq->tail < head) { + len = rq->ring->size - head; + memcpy(ring, vaddr + head, len); + head = 0; + } + memcpy(ring + len, vaddr + head, size - len); + + hexdump(m, ring, size); + kfree(ring); + } +} + +void i915_sched_show(struct drm_printer *m, + struct i915_sched *se, + void (*show_request)(struct drm_printer *m, + const struct i915_request *rq, + const char *prefix, + int indent), + unsigned int max) +{ + const struct i915_request *rq, *last; + unsigned long flags; + unsigned int count; + struct rb_node *rb; + + rcu_read_lock(); + spin_lock_irqsave(&se->lock, flags); + + rq = se->active_request(se); + if (rq) { + i915_request_show(m, rq, "\t\tactive ", 0); + + drm_printf(m, "\t\tring->start: 0x%08x\n", + i915_ggtt_offset(rq->ring->vma)); + drm_printf(m, "\t\tring->head: 0x%08x\n", + rq->ring->head); + drm_printf(m, "\t\tring->tail: 0x%08x\n", + rq->ring->tail); + drm_printf(m, "\t\tring->emit: 0x%08x\n", + rq->ring->emit); + drm_printf(m, "\t\tring->space: 0x%08x\n", + rq->ring->space); + drm_printf(m, "\t\tring->hwsp: 0x%08x\n", + i915_request_active_timeline(rq)->hwsp_offset); + + print_request_ring(m, rq); + + if (rq->context->lrc_reg_state) { + drm_printf(m, "Logical Ring Context:\n"); + hexdump(m, rq->context->lrc_reg_state, PAGE_SIZE); + } + } + drm_printf(m, "\tOn hold?: %lu\n", list_count(&se->hold)); + + drm_printf(m, "\tTasklet queued? %s (%s)\n", + yesno(test_bit(TASKLET_STATE_SCHED, &se->tasklet.state)), + enableddisabled(!atomic_read(&se->tasklet.count))); + + last = NULL; + count = 0; + list_for_each_entry(rq, &se->requests, sched.link) { + if (count++ < max - 1) + show_request(m, rq, "\t\t", 0); + else + last = rq; + } + if (last) { + if (count > max) { + drm_printf(m, + "\t\t...skipping %d executing requests...\n", + count - max); + } + show_request(m, last, "\t\t", 0); + } + + last = NULL; + count = 0; + for (rb = rb_first_cached(&se->queue); rb; rb = rb_next(rb)) { + struct i915_priolist *p = rb_entry(rb, typeof(*p), node); + + priolist_for_each_request(rq, p) { + if (count++ < max - 1) + show_request(m, rq, "\t\t", 0); + else + last = rq; + } + } + if (last) { + if (count > max) { + drm_printf(m, + "\t\t...skipping %d queued requests...\n", + count - max); + } + show_request(m, last, "\t\t", 0); + } + + list_for_each_entry(rq, &se->hold, sched.link) { + if (count++ < max - 1) + show_request(m, rq, "\t\t", 0); + else + last = rq; + } + if (last) { + if (count > max) { + drm_printf(m, + "\t\t...skipping %d suspended requests...\n", + count - max); + } + show_request(m, last, "\t\t", 0); + } + + spin_unlock_irqrestore(&se->lock, flags); + rcu_read_unlock(); + + if (se->show) + se->show(m, se, show_request, max); +} + #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) #include "selftests/i915_scheduler.c" #endif diff --git a/drivers/gpu/drm/i915/i915_scheduler.h b/drivers/gpu/drm/i915/i915_scheduler.h index e2e8b90adb66..51bca23a5617 100644 --- a/drivers/gpu/drm/i915/i915_scheduler.h +++ b/drivers/gpu/drm/i915/i915_scheduler.h @@ -129,4 +129,12 @@ void i915_request_show_with_schedule(struct drm_printer *m, const char *prefix, int indent); +void i915_sched_show(struct drm_printer *m, + struct i915_sched *se, + void (*show_request)(struct drm_printer *m, + const struct i915_request *rq, + const char *prefix, + int indent), + unsigned int max); + #endif /* _I915_SCHEDULER_H_ */ diff --git a/drivers/gpu/drm/i915/i915_scheduler_types.h b/drivers/gpu/drm/i915/i915_scheduler_types.h index 9a9b8e0d78ae..685280d61581 100644 --- a/drivers/gpu/drm/i915/i915_scheduler_types.h +++ b/drivers/gpu/drm/i915/i915_scheduler_types.h @@ -13,6 +13,7 @@ #include "i915_priolist_types.h" +struct drm_printer; struct i915_request; /** @@ -41,6 +42,14 @@ struct i915_sched { bool (*is_executing)(const struct i915_request *rq); + void (*show)(struct drm_printer *m, + struct i915_sched *se, + void (*show_request)(struct drm_printer *m, + const struct i915_request *rq, + const char *prefix, + int indent), + unsigned int max); + struct list_head requests; /* active request, on HW */ struct list_head hold; /* ready requests, but on hold */ /**