Message ID | 20210201085715.27435-27-chris@chris-wilson.co.uk (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [01/57] drm/i915/gt: Restrict the GT clock override to just Icelake | expand |
On 01/02/2021 08:56, Chris Wilson wrote: > 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 <chris@chris-wilson.co.uk> > --- > 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 */ > /** > Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Regards, Tvrtko
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 */ /**
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 <chris@chris-wilson.co.uk> --- 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(-)