diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2018-09-03 11:23:04 -0400 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2018-09-03 12:55:59 -0400 |
commit | d6acae363e63d655ba892c139ba14f24206462c0 (patch) | |
tree | f92ecf6401109a9f619448ded1dd5f49e5567e8a | |
parent | a0e731f4e26c4d774e71f9e69fff3e88d49dd34f (diff) |
drm/i915: Use a cached mapping for the physical HWS
Older gen use a physical address for the hardware status page, for which
we use cache-coherent writes. As the writes are into the cpu cache, we use
a normal WB mapped page to read the HWS, used for our seqno tracking.
Anecdotally, I observed lost breadcrumbs writes into the HWS on i965gm,
which so far have not reoccurred with this patch. How reliable that
evidence is remains to be seen.
v2: Explicitly pass the expected physical address to the hw
v3: Also remember the wild writes we once had for HWS above 4G.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Daniel Vetter <daniel@ffwll.ch>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Reviewed-by: Daniel Vetter <daniel@ffwll.ch>
Link: https://patchwork.freedesktop.org/patch/msgid/20180903152304.31589-2-chris@chris-wilson.co.uk
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_engine_cs.c | 25 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_ringbuffer.c | 7 |
3 files changed, 18 insertions, 15 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9771f39d99b3..5a4da5b723fd 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -1666,7 +1666,6 @@ struct drm_i915_private { | |||
1666 | struct intel_engine_cs *engine_class[MAX_ENGINE_CLASS + 1] | 1666 | struct intel_engine_cs *engine_class[MAX_ENGINE_CLASS + 1] |
1667 | [MAX_ENGINE_INSTANCE + 1]; | 1667 | [MAX_ENGINE_INSTANCE + 1]; |
1668 | 1668 | ||
1669 | struct drm_dma_handle *status_page_dmah; | ||
1670 | struct resource mch_res; | 1669 | struct resource mch_res; |
1671 | 1670 | ||
1672 | /* protects the irq masks */ | 1671 | /* protects the irq masks */ |
diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 292eae19fce2..10cd051ba29e 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c | |||
@@ -532,11 +532,11 @@ void intel_engine_cleanup_scratch(struct intel_engine_cs *engine) | |||
532 | 532 | ||
533 | static void cleanup_status_page(struct intel_engine_cs *engine) | 533 | static void cleanup_status_page(struct intel_engine_cs *engine) |
534 | { | 534 | { |
535 | struct drm_dma_handle *dmah; | 535 | if (HWS_NEEDS_PHYSICAL(engine->i915)) { |
536 | void *addr = fetch_and_zero(&engine->status_page.page_addr); | ||
536 | 537 | ||
537 | dmah = fetch_and_zero(&engine->i915->status_page_dmah); | 538 | __free_page(virt_to_page(addr)); |
538 | if (dmah) | 539 | } |
539 | drm_pci_free(&engine->i915->drm, dmah); | ||
540 | 540 | ||
541 | i915_vma_unpin_and_release(&engine->status_page.vma, | 541 | i915_vma_unpin_and_release(&engine->status_page.vma, |
542 | I915_VMA_RELEASE_MAP); | 542 | I915_VMA_RELEASE_MAP); |
@@ -605,17 +605,18 @@ err: | |||
605 | 605 | ||
606 | static int init_phys_status_page(struct intel_engine_cs *engine) | 606 | static int init_phys_status_page(struct intel_engine_cs *engine) |
607 | { | 607 | { |
608 | struct drm_i915_private *dev_priv = engine->i915; | 608 | struct page *page; |
609 | |||
610 | GEM_BUG_ON(engine->id != RCS); | ||
611 | 609 | ||
612 | dev_priv->status_page_dmah = | 610 | /* |
613 | drm_pci_alloc(&dev_priv->drm, PAGE_SIZE, PAGE_SIZE); | 611 | * Though the HWS register does support 36bit addresses, historically |
614 | if (!dev_priv->status_page_dmah) | 612 | * we have had hangs and corruption reported due to wild writes if |
613 | * the HWS is placed above 4G. | ||
614 | */ | ||
615 | page = alloc_page(GFP_KERNEL | __GFP_DMA32 | __GFP_ZERO); | ||
616 | if (!page) | ||
615 | return -ENOMEM; | 617 | return -ENOMEM; |
616 | 618 | ||
617 | engine->status_page.page_addr = dev_priv->status_page_dmah->vaddr; | 619 | engine->status_page.page_addr = page_address(page); |
618 | memset(engine->status_page.page_addr, 0, PAGE_SIZE); | ||
619 | 620 | ||
620 | return 0; | 621 | return 0; |
621 | } | 622 | } |
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 44432677160c..86604dd1c5a5 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c | |||
@@ -344,11 +344,14 @@ gen7_render_ring_flush(struct i915_request *rq, u32 mode) | |||
344 | static void ring_setup_phys_status_page(struct intel_engine_cs *engine) | 344 | static void ring_setup_phys_status_page(struct intel_engine_cs *engine) |
345 | { | 345 | { |
346 | struct drm_i915_private *dev_priv = engine->i915; | 346 | struct drm_i915_private *dev_priv = engine->i915; |
347 | struct page *page = virt_to_page(engine->status_page.page_addr); | ||
348 | phys_addr_t phys = PFN_PHYS(page_to_pfn(page)); | ||
347 | u32 addr; | 349 | u32 addr; |
348 | 350 | ||
349 | addr = dev_priv->status_page_dmah->busaddr; | 351 | addr = lower_32_bits(phys); |
350 | if (INTEL_GEN(dev_priv) >= 4) | 352 | if (INTEL_GEN(dev_priv) >= 4) |
351 | addr |= (dev_priv->status_page_dmah->busaddr >> 28) & 0xf0; | 353 | addr |= (phys >> 28) & 0xf0; |
354 | |||
352 | I915_WRITE(HWS_PGA, addr); | 355 | I915_WRITE(HWS_PGA, addr); |
353 | } | 356 | } |
354 | 357 | ||