| @@ -208,9 +208,9 @@ · 207 unmodified lines |
| 208 | 208 | |
| 209 | 209 | /* Typical size of the average request (2 pipecontrols and a MI_BB) */ |
| 210 | 210 | #define EXECLISTS_REQUEST_SIZE 64 /* bytes */ |
| 211 | | − |
| 212 | 211 | #define WA_TAIL_DWORDS 2 |
| 213 | 212 | #define WA_TAIL_BYTES (sizeof(u32) * WA_TAIL_DWORDS) |
| 213 | +#define PREEMPT_ID 0x1 |
| 214 | 214 | |
| 215 | 215 | static int execlists_context_deferred_alloc(struct i915_gem_context *ctx, |
| 216 | 216 | struct intel_engine_cs *engine); |
| @@ -429,6 +429,12 @@ static u64 execlists_update_context(struct drm_i915_gem_request *rq) · 212 unmodified lines |
| 429 | 429 | return ce->lrc_desc; |
| 430 | 430 | } |
| 431 | 431 | |
| 432 | +static inline void elsp_write(u64 desc, u32 __iomem *elsp) |
| 433 | +{ |
| 434 | + writel(upper_32_bits(desc), elsp); |
| 435 | + writel(lower_32_bits(desc), elsp); |
| 436 | +} |
| 437 | + |
| 432 | 438 | static void execlists_submit_ports(struct intel_engine_cs *engine) |
| 433 | 439 | { |
| 434 | 440 | struct execlist_port *port = engine->execlists.port; |
| @@ -454,8 +460,7 @@ static void execlists_submit_ports(struct intel_engine_cs *engine) · 19 unmodified lines |
| 454 | 460 | desc = 0; |
| 455 | 461 | } |
| 456 | 462 | |
| 457 | | − writel(upper_32_bits(desc), elsp); |
| 458 | | − writel(lower_32_bits(desc), elsp); |
| 463 | + elsp_write(desc, elsp); |
| 459 | 464 | } |
| 460 | 465 | } |
| 461 | 466 | |
| @@ -488,26 +493,43 @@ static void port_assign(struct execlist_port *port, · 26 unmodified lines |
| 488 | 493 | port_set(port, port_pack(i915_gem_request_get(rq), port_count(port))); |
| 489 | 494 | } |
| 490 | 495 | |
| 496 | +static void inject_preempt_context(struct intel_engine_cs *engine) |
| 497 | +{ |
| 498 | + struct intel_context *ce = |
| 499 | + &engine->i915->preempt_context->engine[engine->id]; |
| 500 | + u32 __iomem *elsp = |
| 501 | + engine->i915->regs + i915_mmio_reg_offset(RING_ELSP(engine)); |
| 502 | + unsigned int n; |
| 503 | + |
| 504 | + GEM_BUG_ON(engine->i915->preempt_context->hw_id != PREEMPT_ID); |
| 505 | + GEM_BUG_ON(!IS_ALIGNED(ce->ring->size, WA_TAIL_BYTES)); |
| 506 | + |
| 507 | + memset(ce->ring->vaddr + ce->ring->tail, 0, WA_TAIL_BYTES); |
| 508 | + ce->ring->tail += WA_TAIL_BYTES; |
| 509 | + ce->ring->tail &= (ce->ring->size - 1); |
| 510 | + ce->lrc_reg_state[CTX_RING_TAIL+1] = ce->ring->tail; |
| 511 | + |
| 512 | + for (n = execlists_num_ports(&engine->execlists); --n; ) |
| 513 | + elsp_write(0, elsp); |
| 514 | + |
| 515 | + elsp_write(ce->lrc_desc, elsp); |
| 516 | +} |
| 517 | + |
| 518 | +static bool can_preempt(struct intel_engine_cs *engine) |
| 519 | +{ |
| 520 | + return INTEL_INFO(engine->i915)->has_logical_ring_preemption; |
| 521 | +} |
| 522 | + |
| 491 | 523 | static void execlists_dequeue(struct intel_engine_cs *engine) |
| 492 | 524 | { |
| 493 | | − struct drm_i915_gem_request *last; |
| 494 | 525 | struct intel_engine_execlists * const execlists = &engine->execlists; |
| 495 | 526 | struct execlist_port *port = execlists->port; |
| 496 | 527 | const struct execlist_port * const last_port = |
| 497 | 528 | &execlists->port[execlists->port_mask]; |
| 529 | + struct drm_i915_gem_request *last = port_request(port); |
| 498 | 530 | struct rb_node *rb; |
| 499 | 531 | bool submit = false; |
| 500 | 532 | |
| 501 | | − last = port_request(port); |
| 502 | | − if (last) |
| 503 | | − /* WaIdleLiteRestore:bdw,skl |
| 504 | | − * Apply the wa NOOPs to prevent ring:HEAD == req:TAIL |
| 505 | | − * as we resubmit the request. See gen8_emit_breadcrumb() |
| 506 | | − * for where we prepare the padding after the end of the |
| 507 | | − * request. |
| 508 | | − */ |
| 509 | | − last->tail = last->wa_tail; |
| 510 | | − |
| 511 | 533 | /* Hardware submission is through 2 ports. Conceptually each port |
| 512 | 534 | * has a (RING_START, RING_HEAD, RING_TAIL) tuple. RING_START is |
| 513 | 535 | * static for a context, and unique to each, so we only execute |
| @@ -532,7 +554,65 @@ static void execlists_dequeue(struct intel_engine_cs *engine) · 18 unmodified lines |
| 532 | 554 | spin_lock_irq(&engine->timeline->lock); |
| 533 | 555 | rb = execlists->first; |
| 534 | 556 | GEM_BUG_ON(rb_first(&execlists->queue) != rb); |
| 535 | | − while (rb) { |
| 557 | + if (!rb) |
| 558 | + goto unlock; |
| 559 | + |
| 560 | + if (last) { |
| 561 | + /* |
| 562 | + * Don't resubmit or switch until all outstanding |
| 563 | + * preemptions (lite-restore) are seen. Then we |
| 564 | + * know the next preemption status we see corresponds |
| 565 | + * to this ELSP update. |
| 566 | + */ |
| 567 | + if (port_count(&port[0]) > 1) |
| 568 | + goto unlock; |
| 569 | + |
| 570 | + if (can_preempt(engine) && |
| 571 | + rb_entry(rb, struct i915_priolist, node)->priority > |
| 572 | + max(last->priotree.priority, 0)) { |
| 573 | + /* |
| 574 | + * Switch to our empty preempt context so |
| 575 | + * the state of the GPU is known (idle). |
| 576 | + */ |
| 577 | + inject_preempt_context(engine); |
| 578 | + execlists->preempt = true; |
| 579 | + goto unlock; |
| 580 | + } else { |
| 581 | + /* |
| 582 | + * In theory, we could coalesce more requests onto |
| 583 | + * the second port (the first port is active, with |
| 584 | + * no preemptions pending). However, that means we |
| 585 | + * then have to deal with the possible lite-restore |
| 586 | + * of the second port (as we submit the ELSP, there |
| 587 | + * may be a context-switch) but also we may complete |
| 588 | + * the resubmission before the context-switch. Ergo, |
| 589 | + * coalescing onto the second port will cause a |
| 590 | + * preemption event, but we cannot predict whether |
| 591 | + * that will affect port[0] or port[1]. |
| 592 | + * |
| 593 | + * If the second port is already active, we can wait |
| 594 | + * until the next context-switch before contemplating |
| 595 | + * new requests. The GPU will be busy and we should be |
| 596 | + * able to resubmit the new ELSP before it idles, |
| 597 | + * avoiding pipeline bubbles (momentary pauses where |
| 598 | + * the driver is unable to keep up the supply of new |
| 599 | + * work). |
| 600 | + */ |
| 601 | + if (port_count(&port[1])) |
| 602 | + goto unlock; |
| 603 | + |
| 604 | + /* WaIdleLiteRestore:bdw,skl |
| 605 | + * Apply the wa NOOPs to prevent |
| 606 | + * ring:HEAD == req:TAIL as we resubmit the |
| 607 | + * request. See gen8_emit_breadcrumb() for |
| 608 | + * where we prepare the padding after the |
| 609 | + * end of the request. |
| 610 | + */ |
| 611 | + last->tail = last->wa_tail; |
| 612 | + } |
| 613 | + } |
| 614 | + |
| 615 | + do { |
| 536 | 616 | struct i915_priolist *p = rb_entry(rb, typeof(*p), node); |
| 537 | 617 | struct drm_i915_gem_request *rq, *rn; |
| 538 | 618 | |
| @@ -595,11 +675,12 @@ static void execlists_dequeue(struct intel_engine_cs *engine) · 56 unmodified lines |
| 595 | 675 | INIT_LIST_HEAD(&p->requests); |
| 596 | 676 | if (p->priority != I915_PRIORITY_NORMAL) |
| 597 | 677 | kmem_cache_free(engine->i915->priorities, p); |
| 598 | | − } |
| 678 | + } while (rb); |
| 599 | 679 | done: |
| 600 | 680 | execlists->first = rb; |
| 601 | 681 | if (submit) |
| 602 | 682 | port_assign(port, last); |
| 683 | +unlock: |
| 603 | 684 | spin_unlock_irq(&engine->timeline->lock); |
| 604 | 685 | |
| 605 | 686 | if (submit) |
| @@ -680,13 +761,6 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine) · 74 unmodified lines |
| 680 | 761 | spin_unlock_irqrestore(&engine->timeline->lock, flags); |
| 681 | 762 | } |
| 682 | 763 | |
| 683 | | −static bool execlists_elsp_ready(const struct intel_engine_cs *engine) |
| 684 | | −{ |
| 685 | | − const struct execlist_port *port = engine->execlists.port; |
| 686 | | − |
| 687 | | − return port_count(&port[0]) + port_count(&port[1]) < 2; |
| 688 | | −} |
| 689 | | − |
| 690 | 764 | /* |
| 691 | 765 | * Check the unread Context Status Buffers and manage the submission of new |
| 692 | 766 | * contexts to the ELSP accordingly. |
| @@ -695,7 +769,7 @@ static void intel_lrc_irq_handler(unsigned long data) · 2 unmodified lines |
| 695 | 769 | { |
| 696 | 770 | struct intel_engine_cs * const engine = (struct intel_engine_cs *)data; |
| 697 | 771 | struct intel_engine_execlists * const execlists = &engine->execlists; |
| 698 | | − struct execlist_port *port = execlists->port; |
| 772 | + struct execlist_port * const port = execlists->port; |
| 699 | 773 | struct drm_i915_private *dev_priv = engine->i915; |
| 700 | 774 | |
| 701 | 775 | /* We can skip acquiring intel_runtime_pm_get() here as it was taken |
| @@ -780,6 +854,23 @@ static void intel_lrc_irq_handler(unsigned long data) · 78 unmodified lines |
| 780 | 854 | if (!(status & GEN8_CTX_STATUS_COMPLETED_MASK)) |
| 781 | 855 | continue; |
| 782 | 856 | |
| 857 | + if (status & GEN8_CTX_STATUS_ACTIVE_IDLE && |
| 858 | + buf[2*head + 1] == PREEMPT_ID) { |
| 859 | + execlist_cancel_port_requests(execlists); |
| 860 | + |
| 861 | + spin_lock_irq(&engine->timeline->lock); |
| 862 | + unwind_incomplete_requests(engine); |
| 863 | + spin_unlock_irq(&engine->timeline->lock); |
| 864 | + |
| 865 | + GEM_BUG_ON(!execlists->preempt); |
| 866 | + execlists->preempt = false; |
| 867 | + continue; |
| 868 | + } |
| 869 | + |
| 870 | + if (status & GEN8_CTX_STATUS_PREEMPTED && |
| 871 | + execlists->preempt) |
| 872 | + continue; |
| 873 | + |
| 783 | 874 | /* Check the context/desc id for this event matches */ |
| 784 | 875 | GEM_DEBUG_BUG_ON(buf[2 * head + 1] != port->context_id); |
| 785 | 876 | |
| @@ -811,7 +902,7 @@ static void intel_lrc_irq_handler(unsigned long data) · 25 unmodified lines |
| 811 | 902 | } |
| 812 | 903 | } |
| 813 | 904 | |
| 814 | | − if (execlists_elsp_ready(engine)) |
| 905 | + if (!execlists->preempt) |
| 815 | 906 | execlists_dequeue(engine); |
| 816 | 907 | |
| 817 | 908 | intel_uncore_forcewake_put(dev_priv, execlists->fw_domains); |
| @@ -824,7 +915,7 @@ static void insert_request(struct intel_engine_cs *engine, · 6 unmodified lines |
| 824 | 915 | struct i915_priolist *p = lookup_priolist(engine, pt, prio); |
| 825 | 916 | |
| 826 | 917 | list_add_tail(&pt->link, &ptr_mask_bits(p, 1)->requests); |
| 827 | | − if (ptr_unmask_bits(p, 1) && execlists_elsp_ready(engine)) |
| 918 | + if (ptr_unmask_bits(p, 1)) |
| 828 | 919 | tasklet_hi_schedule(&engine->execlists.irq_tasklet); |
| 829 | 920 | } |
| 830 | 921 | |
| @@ -954,8 +1045,6 @@ static void execlists_schedule(struct drm_i915_gem_request *request, int prio) · 123 unmodified lines |
| 954 | 1045 | } |
| 955 | 1046 | |
| 956 | 1047 | spin_unlock_irq(&engine->timeline->lock); |
| 957 | | − |
| 958 | | − /* XXX Do we need to preempt to make room for us and our deps? */ |
| 959 | 1048 | } |
| 960 | 1049 | |
| 961 | 1050 | static struct intel_ring * |
| @@ -1151,6 +1240,8 @@ static u32 *gen8_init_indirectctx_bb(struct intel_engine_cs *engine, u32 *batch) · 189 unmodified lines |
| 1151 | 1240 | i915_ggtt_offset(engine->scratch) + |
| 1152 | 1241 | 2 * CACHELINE_BYTES); |
| 1153 | 1242 | |
| 1243 | + *batch++ = MI_ARB_ON_OFF | MI_ARB_ENABLE; |
| 1244 | + |
| 1154 | 1245 | /* Pad to end of cacheline */ |
| 1155 | 1246 | while ((unsigned long)batch % CACHELINE_BYTES) |
| 1156 | 1247 | *batch++ = MI_NOOP; |
| @@ -1166,6 +1257,8 @@ static u32 *gen8_init_indirectctx_bb(struct intel_engine_cs *engine, u32 *batch) · 9 unmodified lines |
| 1166 | 1257 | |
| 1167 | 1258 | static u32 *gen9_init_indirectctx_bb(struct intel_engine_cs *engine, u32 *batch) |
| 1168 | 1259 | { |
| 1260 | + *batch++ = MI_ARB_ON_OFF | MI_ARB_DISABLE; |
| 1261 | + |
| 1169 | 1262 | /* WaFlushCoherentL3CacheLinesAtContextSwitch:skl,bxt,glk */ |
| 1170 | 1263 | batch = gen8_emit_flush_coherentl3_wa(engine, batch); |
| 1171 | 1264 | |
| @@ -1211,6 +1304,8 @@ static u32 *gen9_init_indirectctx_bb(struct intel_engine_cs *engine, u32 *batch) · 39 unmodified lines |
| 1211 | 1304 | *batch++ = 0; |
| 1212 | 1305 | } |
| 1213 | 1306 | |
| 1307 | + *batch++ = MI_ARB_ON_OFF | MI_ARB_ENABLE; |
| 1308 | + |
| 1214 | 1309 | /* Pad to end of cacheline */ |
| 1215 | 1310 | while ((unsigned long)batch % CACHELINE_BYTES) |
| 1216 | 1311 | *batch++ = MI_NOOP; |
| @@ -1364,6 +1459,7 @@ static int gen8_init_common_ring(struct intel_engine_cs *engine) · 147 unmodified lines |
| 1364 | 1459 | GT_CONTEXT_SWITCH_INTERRUPT << engine->irq_shift); |
| 1365 | 1460 | clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); |
| 1366 | 1461 | execlists->csb_head = -1; |
| 1462 | + execlists->preempt = false; |
| 1367 | 1463 | |
| 1368 | 1464 | /* After a GPU reset, we may have requests to replay */ |
| 1369 | 1465 | if (!i915_modparams.enable_guc_submission && execlists->first) |
| @@ -1659,7 +1755,8 @@ static int gen8_emit_flush_render(struct drm_i915_gem_request *request, · 289 unmodified lines |
| 1659 | 1755 | */ |
| 1660 | 1756 | static void gen8_emit_wa_tail(struct drm_i915_gem_request *request, u32 *cs) |
| 1661 | 1757 | { |
| 1662 | | − *cs++ = MI_NOOP; |
| 1758 | + /* Ensure there's always at least one preemption point per-request. */ |
| 1759 | + *cs++ = MI_ARB_CHECK; |
| 1663 | 1760 | *cs++ = MI_NOOP; |
| 1664 | 1761 | request->wa_tail = intel_ring_offset(request, cs); |
| 1665 | 1762 | } |
| @@ -1680,7 +1777,6 @@ static void gen8_emit_breadcrumb(struct drm_i915_gem_request *request, u32 *cs) · 14 unmodified lines |
| 1680 | 1777 | |
| 1681 | 1778 | gen8_emit_wa_tail(request, cs); |
| 1682 | 1779 | } |
| 1683 | | − |
| 1684 | 1780 | static const int gen8_emit_breadcrumb_sz = 6 + WA_TAIL_DWORDS; |
| 1685 | 1781 | |
| 1686 | 1782 | static void gen8_emit_breadcrumb_render(struct drm_i915_gem_request *request, |
| @@ -1708,7 +1804,6 @@ static void gen8_emit_breadcrumb_render(struct drm_i915_gem_request *request, · 21 unmodified lines |
| 1708 | 1804 | |
| 1709 | 1805 | gen8_emit_wa_tail(request, cs); |
| 1710 | 1806 | } |
| 1711 | | − |
| 1712 | 1807 | static const int gen8_emit_breadcrumb_render_sz = 8 + WA_TAIL_DWORDS; |
| 1713 | 1808 | |
| 1714 | 1809 | static int gen8_init_rcs_context(struct drm_i915_gem_request *req) |