Skip to content

Commit 486e93f

Browse files
dceraoloickle
authored andcommitted
drm/i915/lrc: allocate separate page for HWSP
On gen8+ we're currently using the PPHWSP of the kernel ctx as the global HWSP. However, when the kernel ctx gets submitted (e.g. from __intel_autoenable_gt_powersave) the HW will use that page as both HWSP and PPHWSP. This causes a conflict in the register arena of the HWSP, i.e. dword indices below 0x30. We don't current utilize this arena, but in the following patches we will take advantage of the cached register state for handling execlist's context status interrupt. To avoid the conflict, instead of re-using the PPHWSP of the kernel ctx we can allocate a separate page for the HWSP like what happens for pre-execlists platform. v2: Add a use-case for the register arena of the HWSP. Signed-off-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com> Cc: Michel Thierry <michel.thierry@intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/1499357440-34688-1-git-send-email-daniele.ceraolospurio@intel.com Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Michel Thierry <michel.thierry@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20170913085605.18299-3-chris@chris-wilson.co.uk
1 parent a922c0c commit 486e93f

File tree

3 files changed

+127
-158
lines changed

3 files changed

+127
-158
lines changed

drivers/gpu/drm/i915/intel_engine_cs.c

Lines changed: 125 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,114 @@ static void intel_engine_cleanup_scratch(struct intel_engine_cs *engine)
442442
i915_vma_unpin_and_release(&engine->scratch);
443443
}
444444

445+
static void cleanup_phys_status_page(struct intel_engine_cs *engine)
446+
{
447+
struct drm_i915_private *dev_priv = engine->i915;
448+
449+
if (!dev_priv->status_page_dmah)
450+
return;
451+
452+
drm_pci_free(&dev_priv->drm, dev_priv->status_page_dmah);
453+
engine->status_page.page_addr = NULL;
454+
}
455+
456+
static void cleanup_status_page(struct intel_engine_cs *engine)
457+
{
458+
struct i915_vma *vma;
459+
struct drm_i915_gem_object *obj;
460+
461+
vma = fetch_and_zero(&engine->status_page.vma);
462+
if (!vma)
463+
return;
464+
465+
obj = vma->obj;
466+
467+
i915_vma_unpin(vma);
468+
i915_vma_close(vma);
469+
470+
i915_gem_object_unpin_map(obj);
471+
__i915_gem_object_release_unless_active(obj);
472+
}
473+
474+
static int init_status_page(struct intel_engine_cs *engine)
475+
{
476+
struct drm_i915_gem_object *obj;
477+
struct i915_vma *vma;
478+
unsigned int flags;
479+
void *vaddr;
480+
int ret;
481+
482+
obj = i915_gem_object_create_internal(engine->i915, PAGE_SIZE);
483+
if (IS_ERR(obj)) {
484+
DRM_ERROR("Failed to allocate status page\n");
485+
return PTR_ERR(obj);
486+
}
487+
488+
ret = i915_gem_object_set_cache_level(obj, I915_CACHE_LLC);
489+
if (ret)
490+
goto err;
491+
492+
vma = i915_vma_instance(obj, &engine->i915->ggtt.base, NULL);
493+
if (IS_ERR(vma)) {
494+
ret = PTR_ERR(vma);
495+
goto err;
496+
}
497+
498+
flags = PIN_GLOBAL;
499+
if (!HAS_LLC(engine->i915))
500+
/* On g33, we cannot place HWS above 256MiB, so
501+
* restrict its pinning to the low mappable arena.
502+
* Though this restriction is not documented for
503+
* gen4, gen5, or byt, they also behave similarly
504+
* and hang if the HWS is placed at the top of the
505+
* GTT. To generalise, it appears that all !llc
506+
* platforms have issues with us placing the HWS
507+
* above the mappable region (even though we never
508+
* actually map it).
509+
*/
510+
flags |= PIN_MAPPABLE;
511+
ret = i915_vma_pin(vma, 0, 4096, flags);
512+
if (ret)
513+
goto err;
514+
515+
vaddr = i915_gem_object_pin_map(obj, I915_MAP_WB);
516+
if (IS_ERR(vaddr)) {
517+
ret = PTR_ERR(vaddr);
518+
goto err_unpin;
519+
}
520+
521+
engine->status_page.vma = vma;
522+
engine->status_page.ggtt_offset = i915_ggtt_offset(vma);
523+
engine->status_page.page_addr = memset(vaddr, 0, PAGE_SIZE);
524+
525+
DRM_DEBUG_DRIVER("%s hws offset: 0x%08x\n",
526+
engine->name, i915_ggtt_offset(vma));
527+
return 0;
528+
529+
err_unpin:
530+
i915_vma_unpin(vma);
531+
err:
532+
i915_gem_object_put(obj);
533+
return ret;
534+
}
535+
536+
static int init_phys_status_page(struct intel_engine_cs *engine)
537+
{
538+
struct drm_i915_private *dev_priv = engine->i915;
539+
540+
GEM_BUG_ON(engine->id != RCS);
541+
542+
dev_priv->status_page_dmah =
543+
drm_pci_alloc(&dev_priv->drm, PAGE_SIZE, PAGE_SIZE);
544+
if (!dev_priv->status_page_dmah)
545+
return -ENOMEM;
546+
547+
engine->status_page.page_addr = dev_priv->status_page_dmah->vaddr;
548+
memset(engine->status_page.page_addr, 0, PAGE_SIZE);
549+
550+
return 0;
551+
}
552+
445553
/**
446554
* intel_engines_init_common - initialize cengine state which might require hw access
447555
* @engine: Engine to initialize.
@@ -477,10 +585,21 @@ int intel_engine_init_common(struct intel_engine_cs *engine)
477585

478586
ret = i915_gem_render_state_init(engine);
479587
if (ret)
480-
goto err_unpin;
588+
goto err_breadcrumbs;
589+
590+
if (HWS_NEEDS_PHYSICAL(engine->i915))
591+
ret = init_phys_status_page(engine);
592+
else
593+
ret = init_status_page(engine);
594+
if (ret)
595+
goto err_rs_fini;
481596

482597
return 0;
483598

599+
err_rs_fini:
600+
i915_gem_render_state_fini(engine);
601+
err_breadcrumbs:
602+
intel_engine_fini_breadcrumbs(engine);
484603
err_unpin:
485604
engine->context_unpin(engine, engine->i915->kernel_context);
486605
return ret;
@@ -497,6 +616,11 @@ void intel_engine_cleanup_common(struct intel_engine_cs *engine)
497616
{
498617
intel_engine_cleanup_scratch(engine);
499618

619+
if (HWS_NEEDS_PHYSICAL(engine->i915))
620+
cleanup_phys_status_page(engine);
621+
else
622+
cleanup_status_page(engine);
623+
500624
i915_gem_render_state_fini(engine);
501625
intel_engine_fini_breadcrumbs(engine);
502626
intel_engine_cleanup_cmd_parser(engine);

drivers/gpu/drm/i915/intel_lrc.c

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1674,11 +1674,6 @@ void intel_logical_ring_cleanup(struct intel_engine_cs *engine)
16741674
if (engine->cleanup)
16751675
engine->cleanup(engine);
16761676

1677-
if (engine->status_page.vma) {
1678-
i915_gem_object_unpin_map(engine->status_page.vma->obj);
1679-
engine->status_page.vma = NULL;
1680-
}
1681-
16821677
intel_engine_cleanup_common(engine);
16831678

16841679
lrc_destroy_wa_ctx(engine);
@@ -1725,24 +1720,6 @@ logical_ring_default_irqs(struct intel_engine_cs *engine)
17251720
engine->irq_keep_mask = GT_CONTEXT_SWITCH_INTERRUPT << shift;
17261721
}
17271722

1728-
static int
1729-
lrc_setup_hws(struct intel_engine_cs *engine, struct i915_vma *vma)
1730-
{
1731-
const int hws_offset = LRC_PPHWSP_PN * PAGE_SIZE;
1732-
void *hws;
1733-
1734-
/* The HWSP is part of the default context object in LRC mode. */
1735-
hws = i915_gem_object_pin_map(vma->obj, I915_MAP_WB);
1736-
if (IS_ERR(hws))
1737-
return PTR_ERR(hws);
1738-
1739-
engine->status_page.page_addr = hws + hws_offset;
1740-
engine->status_page.ggtt_offset = i915_ggtt_offset(vma) + hws_offset;
1741-
engine->status_page.vma = vma;
1742-
1743-
return 0;
1744-
}
1745-
17461723
static void
17471724
logical_ring_setup(struct intel_engine_cs *engine)
17481725
{
@@ -1775,23 +1752,14 @@ logical_ring_setup(struct intel_engine_cs *engine)
17751752
logical_ring_default_irqs(engine);
17761753
}
17771754

1778-
static int
1779-
logical_ring_init(struct intel_engine_cs *engine)
1755+
static int logical_ring_init(struct intel_engine_cs *engine)
17801756
{
1781-
struct i915_gem_context *dctx = engine->i915->kernel_context;
17821757
int ret;
17831758

17841759
ret = intel_engine_init_common(engine);
17851760
if (ret)
17861761
goto error;
17871762

1788-
/* And setup the hardware status page. */
1789-
ret = lrc_setup_hws(engine, dctx->engine[engine->id].state);
1790-
if (ret) {
1791-
DRM_ERROR("Failed to set up hws %s: %d\n", engine->name, ret);
1792-
goto error;
1793-
}
1794-
17951763
return 0;
17961764

17971765
error:

drivers/gpu/drm/i915/intel_ringbuffer.c

Lines changed: 1 addition & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -1175,113 +1175,7 @@ i915_emit_bb_start(struct drm_i915_gem_request *req,
11751175
return 0;
11761176
}
11771177

1178-
static void cleanup_phys_status_page(struct intel_engine_cs *engine)
1179-
{
1180-
struct drm_i915_private *dev_priv = engine->i915;
1181-
1182-
if (!dev_priv->status_page_dmah)
1183-
return;
1184-
1185-
drm_pci_free(&dev_priv->drm, dev_priv->status_page_dmah);
1186-
engine->status_page.page_addr = NULL;
1187-
}
1188-
1189-
static void cleanup_status_page(struct intel_engine_cs *engine)
1190-
{
1191-
struct i915_vma *vma;
1192-
struct drm_i915_gem_object *obj;
1193-
1194-
vma = fetch_and_zero(&engine->status_page.vma);
1195-
if (!vma)
1196-
return;
1197-
1198-
obj = vma->obj;
1199-
1200-
i915_vma_unpin(vma);
1201-
i915_vma_close(vma);
1202-
1203-
i915_gem_object_unpin_map(obj);
1204-
__i915_gem_object_release_unless_active(obj);
1205-
}
12061178

1207-
static int init_status_page(struct intel_engine_cs *engine)
1208-
{
1209-
struct drm_i915_gem_object *obj;
1210-
struct i915_vma *vma;
1211-
unsigned int flags;
1212-
void *vaddr;
1213-
int ret;
1214-
1215-
obj = i915_gem_object_create_internal(engine->i915, PAGE_SIZE);
1216-
if (IS_ERR(obj)) {
1217-
DRM_ERROR("Failed to allocate status page\n");
1218-
return PTR_ERR(obj);
1219-
}
1220-
1221-
ret = i915_gem_object_set_cache_level(obj, I915_CACHE_LLC);
1222-
if (ret)
1223-
goto err;
1224-
1225-
vma = i915_vma_instance(obj, &engine->i915->ggtt.base, NULL);
1226-
if (IS_ERR(vma)) {
1227-
ret = PTR_ERR(vma);
1228-
goto err;
1229-
}
1230-
1231-
flags = PIN_GLOBAL;
1232-
if (!HAS_LLC(engine->i915))
1233-
/* On g33, we cannot place HWS above 256MiB, so
1234-
* restrict its pinning to the low mappable arena.
1235-
* Though this restriction is not documented for
1236-
* gen4, gen5, or byt, they also behave similarly
1237-
* and hang if the HWS is placed at the top of the
1238-
* GTT. To generalise, it appears that all !llc
1239-
* platforms have issues with us placing the HWS
1240-
* above the mappable region (even though we never
1241-
* actualy map it).
1242-
*/
1243-
flags |= PIN_MAPPABLE;
1244-
ret = i915_vma_pin(vma, 0, 4096, flags);
1245-
if (ret)
1246-
goto err;
1247-
1248-
vaddr = i915_gem_object_pin_map(obj, I915_MAP_WB);
1249-
if (IS_ERR(vaddr)) {
1250-
ret = PTR_ERR(vaddr);
1251-
goto err_unpin;
1252-
}
1253-
1254-
engine->status_page.vma = vma;
1255-
engine->status_page.ggtt_offset = i915_ggtt_offset(vma);
1256-
engine->status_page.page_addr = memset(vaddr, 0, PAGE_SIZE);
1257-
1258-
DRM_DEBUG_DRIVER("%s hws offset: 0x%08x\n",
1259-
engine->name, i915_ggtt_offset(vma));
1260-
return 0;
1261-
1262-
err_unpin:
1263-
i915_vma_unpin(vma);
1264-
err:
1265-
i915_gem_object_put(obj);
1266-
return ret;
1267-
}
1268-
1269-
static int init_phys_status_page(struct intel_engine_cs *engine)
1270-
{
1271-
struct drm_i915_private *dev_priv = engine->i915;
1272-
1273-
GEM_BUG_ON(engine->id != RCS);
1274-
1275-
dev_priv->status_page_dmah =
1276-
drm_pci_alloc(&dev_priv->drm, PAGE_SIZE, PAGE_SIZE);
1277-
if (!dev_priv->status_page_dmah)
1278-
return -ENOMEM;
1279-
1280-
engine->status_page.page_addr = dev_priv->status_page_dmah->vaddr;
1281-
memset(engine->status_page.page_addr, 0, PAGE_SIZE);
1282-
1283-
return 0;
1284-
}
12851179

12861180
int intel_ring_pin(struct intel_ring *ring,
12871181
struct drm_i915_private *i915,
@@ -1568,17 +1462,10 @@ static int intel_init_ring_buffer(struct intel_engine_cs *engine)
15681462
if (err)
15691463
goto err;
15701464

1571-
if (HWS_NEEDS_PHYSICAL(engine->i915))
1572-
err = init_phys_status_page(engine);
1573-
else
1574-
err = init_status_page(engine);
1575-
if (err)
1576-
goto err;
1577-
15781465
ring = intel_engine_create_ring(engine, 32 * PAGE_SIZE);
15791466
if (IS_ERR(ring)) {
15801467
err = PTR_ERR(ring);
1581-
goto err_hws;
1468+
goto err;
15821469
}
15831470

15841471
/* Ring wraparound at offset 0 sometimes hangs. No idea why. */
@@ -1593,11 +1480,6 @@ static int intel_init_ring_buffer(struct intel_engine_cs *engine)
15931480

15941481
err_ring:
15951482
intel_ring_free(ring);
1596-
err_hws:
1597-
if (HWS_NEEDS_PHYSICAL(engine->i915))
1598-
cleanup_phys_status_page(engine);
1599-
else
1600-
cleanup_status_page(engine);
16011483
err:
16021484
intel_engine_cleanup_common(engine);
16031485
return err;
@@ -1616,11 +1498,6 @@ void intel_engine_cleanup(struct intel_engine_cs *engine)
16161498
if (engine->cleanup)
16171499
engine->cleanup(engine);
16181500

1619-
if (HWS_NEEDS_PHYSICAL(dev_priv))
1620-
cleanup_phys_status_page(engine);
1621-
else
1622-
cleanup_status_page(engine);
1623-
16241501
intel_engine_cleanup_common(engine);
16251502

16261503
dev_priv->engine[engine->id] = NULL;

0 commit comments

Comments
 (0)