Commit 2c8ab333 authored by Maarten Lankhorst's avatar Maarten Lankhorst Committed by Daniel Vetter

drm/i915: Pin timeline map after first timeline pin, v4.

We're starting to require the reservation lock for pinning,
so wait until we have that.

Update the selftests to handle this correctly, and ensure pin is
called in live_hwsp_rollover_user() and mock_hwsp_freelist().

Changes since v1:
- Fix NULL + XX arithmatic, use casts. (kbuild)
Changes since v2:
- Clear entire cacheline when pinning.
Changes since v3:
- CACHELINE_BYTES -> TIMELINE_SEQNO_BYTES. (jekstrand)
Signed-off-by: default avatarMaarten Lankhorst <maarten.lankhorst@linux.intel.com>
Reported-by: default avatarkernel test robot <lkp@intel.com>
Reviewed-by: default avatarThomas Hellström <thomas.hellstrom@linux.intel.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Link: https://patchwork.freedesktop.org/patch/msgid/20210323155059.628690-3-maarten.lankhorst@linux.intel.com
parent 12ca695d
...@@ -53,14 +53,29 @@ static int __timeline_active(struct i915_active *active) ...@@ -53,14 +53,29 @@ static int __timeline_active(struct i915_active *active)
return 0; return 0;
} }
I915_SELFTEST_EXPORT int
intel_timeline_pin_map(struct intel_timeline *timeline)
{
struct drm_i915_gem_object *obj = timeline->hwsp_ggtt->obj;
u32 ofs = offset_in_page(timeline->hwsp_offset);
void *vaddr;
vaddr = i915_gem_object_pin_map(obj, I915_MAP_WB);
if (IS_ERR(vaddr))
return PTR_ERR(vaddr);
timeline->hwsp_map = vaddr;
timeline->hwsp_seqno = memset(vaddr + ofs, 0, TIMELINE_SEQNO_BYTES);
clflush(vaddr + ofs);
return 0;
}
static int intel_timeline_init(struct intel_timeline *timeline, static int intel_timeline_init(struct intel_timeline *timeline,
struct intel_gt *gt, struct intel_gt *gt,
struct i915_vma *hwsp, struct i915_vma *hwsp,
unsigned int offset) unsigned int offset)
{ {
void *vaddr;
u32 *seqno;
kref_init(&timeline->kref); kref_init(&timeline->kref);
atomic_set(&timeline->pin_count, 0); atomic_set(&timeline->pin_count, 0);
...@@ -77,14 +92,8 @@ static int intel_timeline_init(struct intel_timeline *timeline, ...@@ -77,14 +92,8 @@ static int intel_timeline_init(struct intel_timeline *timeline,
timeline->hwsp_ggtt = hwsp; timeline->hwsp_ggtt = hwsp;
} }
vaddr = i915_gem_object_pin_map(hwsp->obj, I915_MAP_WB); timeline->hwsp_map = NULL;
if (IS_ERR(vaddr)) timeline->hwsp_seqno = (void *)(long)timeline->hwsp_offset;
return PTR_ERR(vaddr);
timeline->hwsp_map = vaddr;
seqno = vaddr + timeline->hwsp_offset;
WRITE_ONCE(*seqno, 0);
timeline->hwsp_seqno = seqno;
GEM_BUG_ON(timeline->hwsp_offset >= hwsp->size); GEM_BUG_ON(timeline->hwsp_offset >= hwsp->size);
...@@ -114,6 +123,7 @@ static void intel_timeline_fini(struct rcu_head *rcu) ...@@ -114,6 +123,7 @@ static void intel_timeline_fini(struct rcu_head *rcu)
struct intel_timeline *timeline = struct intel_timeline *timeline =
container_of(rcu, struct intel_timeline, rcu); container_of(rcu, struct intel_timeline, rcu);
if (timeline->hwsp_map)
i915_gem_object_unpin_map(timeline->hwsp_ggtt->obj); i915_gem_object_unpin_map(timeline->hwsp_ggtt->obj);
i915_vma_put(timeline->hwsp_ggtt); i915_vma_put(timeline->hwsp_ggtt);
...@@ -174,6 +184,12 @@ int intel_timeline_pin(struct intel_timeline *tl, struct i915_gem_ww_ctx *ww) ...@@ -174,6 +184,12 @@ int intel_timeline_pin(struct intel_timeline *tl, struct i915_gem_ww_ctx *ww)
if (atomic_add_unless(&tl->pin_count, 1, 0)) if (atomic_add_unless(&tl->pin_count, 1, 0))
return 0; return 0;
if (!tl->hwsp_map) {
err = intel_timeline_pin_map(tl);
if (err)
return err;
}
err = i915_ggtt_pin(tl->hwsp_ggtt, ww, 0, PIN_HIGH); err = i915_ggtt_pin(tl->hwsp_ggtt, ww, 0, PIN_HIGH);
if (err) if (err)
return err; return err;
......
...@@ -117,4 +117,6 @@ intel_timeline_is_last(const struct intel_timeline *tl, ...@@ -117,4 +117,6 @@ intel_timeline_is_last(const struct intel_timeline *tl,
return list_is_last_rcu(&rq->link, &tl->requests); return list_is_last_rcu(&rq->link, &tl->requests);
} }
I915_SELFTEST_DECLARE(int intel_timeline_pin_map(struct intel_timeline *tl));
#endif #endif
...@@ -32,9 +32,20 @@ ...@@ -32,9 +32,20 @@
#include "mock_engine.h" #include "mock_engine.h"
#include "selftests/mock_request.h" #include "selftests/mock_request.h"
static void mock_timeline_pin(struct intel_timeline *tl) static int mock_timeline_pin(struct intel_timeline *tl)
{ {
int err;
if (WARN_ON(!i915_gem_object_trylock(tl->hwsp_ggtt->obj)))
return -EBUSY;
err = intel_timeline_pin_map(tl);
i915_gem_object_unlock(tl->hwsp_ggtt->obj);
if (err)
return err;
atomic_inc(&tl->pin_count); atomic_inc(&tl->pin_count);
return 0;
} }
static void mock_timeline_unpin(struct intel_timeline *tl) static void mock_timeline_unpin(struct intel_timeline *tl)
...@@ -152,6 +163,8 @@ static void mock_context_destroy(struct kref *ref) ...@@ -152,6 +163,8 @@ static void mock_context_destroy(struct kref *ref)
static int mock_context_alloc(struct intel_context *ce) static int mock_context_alloc(struct intel_context *ce)
{ {
int err;
ce->ring = mock_ring(ce->engine); ce->ring = mock_ring(ce->engine);
if (!ce->ring) if (!ce->ring)
return -ENOMEM; return -ENOMEM;
...@@ -162,7 +175,12 @@ static int mock_context_alloc(struct intel_context *ce) ...@@ -162,7 +175,12 @@ static int mock_context_alloc(struct intel_context *ce)
return PTR_ERR(ce->timeline); return PTR_ERR(ce->timeline);
} }
mock_timeline_pin(ce->timeline); err = mock_timeline_pin(ce->timeline);
if (err) {
intel_timeline_put(ce->timeline);
ce->timeline = NULL;
return err;
}
return 0; return 0;
} }
......
...@@ -60,6 +60,7 @@ static void __mock_hwsp_record(struct mock_hwsp_freelist *state, ...@@ -60,6 +60,7 @@ static void __mock_hwsp_record(struct mock_hwsp_freelist *state,
tl = xchg(&state->history[idx], tl); tl = xchg(&state->history[idx], tl);
if (tl) { if (tl) {
radix_tree_delete(&state->cachelines, hwsp_cacheline(tl)); radix_tree_delete(&state->cachelines, hwsp_cacheline(tl));
intel_timeline_unpin(tl);
intel_timeline_put(tl); intel_timeline_put(tl);
} }
} }
...@@ -79,6 +80,12 @@ static int __mock_hwsp_timeline(struct mock_hwsp_freelist *state, ...@@ -79,6 +80,12 @@ static int __mock_hwsp_timeline(struct mock_hwsp_freelist *state,
if (IS_ERR(tl)) if (IS_ERR(tl))
return PTR_ERR(tl); return PTR_ERR(tl);
err = intel_timeline_pin(tl, NULL);
if (err) {
intel_timeline_put(tl);
return err;
}
cacheline = hwsp_cacheline(tl); cacheline = hwsp_cacheline(tl);
err = radix_tree_insert(&state->cachelines, cacheline, tl); err = radix_tree_insert(&state->cachelines, cacheline, tl);
if (err) { if (err) {
...@@ -86,6 +93,7 @@ static int __mock_hwsp_timeline(struct mock_hwsp_freelist *state, ...@@ -86,6 +93,7 @@ static int __mock_hwsp_timeline(struct mock_hwsp_freelist *state,
pr_err("HWSP cacheline %lu already used; duplicate allocation!\n", pr_err("HWSP cacheline %lu already used; duplicate allocation!\n",
cacheline); cacheline);
} }
intel_timeline_unpin(tl);
intel_timeline_put(tl); intel_timeline_put(tl);
return err; return err;
} }
...@@ -453,7 +461,7 @@ static int emit_ggtt_store_dw(struct i915_request *rq, u32 addr, u32 value) ...@@ -453,7 +461,7 @@ static int emit_ggtt_store_dw(struct i915_request *rq, u32 addr, u32 value)
} }
static struct i915_request * static struct i915_request *
tl_write(struct intel_timeline *tl, struct intel_engine_cs *engine, u32 value) checked_tl_write(struct intel_timeline *tl, struct intel_engine_cs *engine, u32 value)
{ {
struct i915_request *rq; struct i915_request *rq;
int err; int err;
...@@ -464,6 +472,13 @@ tl_write(struct intel_timeline *tl, struct intel_engine_cs *engine, u32 value) ...@@ -464,6 +472,13 @@ tl_write(struct intel_timeline *tl, struct intel_engine_cs *engine, u32 value)
goto out; goto out;
} }
if (READ_ONCE(*tl->hwsp_seqno) != tl->seqno) {
pr_err("Timeline created with incorrect breadcrumb, found %x, expected %x\n",
*tl->hwsp_seqno, tl->seqno);
intel_timeline_unpin(tl);
return ERR_PTR(-EINVAL);
}
rq = intel_engine_create_kernel_request(engine); rq = intel_engine_create_kernel_request(engine);
if (IS_ERR(rq)) if (IS_ERR(rq))
goto out_unpin; goto out_unpin;
...@@ -485,25 +500,6 @@ tl_write(struct intel_timeline *tl, struct intel_engine_cs *engine, u32 value) ...@@ -485,25 +500,6 @@ tl_write(struct intel_timeline *tl, struct intel_engine_cs *engine, u32 value)
return rq; return rq;
} }
static struct intel_timeline *
checked_intel_timeline_create(struct intel_gt *gt)
{
struct intel_timeline *tl;
tl = intel_timeline_create(gt);
if (IS_ERR(tl))
return tl;
if (READ_ONCE(*tl->hwsp_seqno) != tl->seqno) {
pr_err("Timeline created with incorrect breadcrumb, found %x, expected %x\n",
*tl->hwsp_seqno, tl->seqno);
intel_timeline_put(tl);
return ERR_PTR(-EINVAL);
}
return tl;
}
static int live_hwsp_engine(void *arg) static int live_hwsp_engine(void *arg)
{ {
#define NUM_TIMELINES 4096 #define NUM_TIMELINES 4096
...@@ -536,13 +532,13 @@ static int live_hwsp_engine(void *arg) ...@@ -536,13 +532,13 @@ static int live_hwsp_engine(void *arg)
struct intel_timeline *tl; struct intel_timeline *tl;
struct i915_request *rq; struct i915_request *rq;
tl = checked_intel_timeline_create(gt); tl = intel_timeline_create(gt);
if (IS_ERR(tl)) { if (IS_ERR(tl)) {
err = PTR_ERR(tl); err = PTR_ERR(tl);
break; break;
} }
rq = tl_write(tl, engine, count); rq = checked_tl_write(tl, engine, count);
if (IS_ERR(rq)) { if (IS_ERR(rq)) {
intel_timeline_put(tl); intel_timeline_put(tl);
err = PTR_ERR(rq); err = PTR_ERR(rq);
...@@ -609,14 +605,14 @@ static int live_hwsp_alternate(void *arg) ...@@ -609,14 +605,14 @@ static int live_hwsp_alternate(void *arg)
if (!intel_engine_can_store_dword(engine)) if (!intel_engine_can_store_dword(engine))
continue; continue;
tl = checked_intel_timeline_create(gt); tl = intel_timeline_create(gt);
if (IS_ERR(tl)) { if (IS_ERR(tl)) {
err = PTR_ERR(tl); err = PTR_ERR(tl);
goto out; goto out;
} }
intel_engine_pm_get(engine); intel_engine_pm_get(engine);
rq = tl_write(tl, engine, count); rq = checked_tl_write(tl, engine, count);
intel_engine_pm_put(engine); intel_engine_pm_put(engine);
if (IS_ERR(rq)) { if (IS_ERR(rq)) {
intel_timeline_put(tl); intel_timeline_put(tl);
...@@ -1259,6 +1255,10 @@ static int live_hwsp_rollover_user(void *arg) ...@@ -1259,6 +1255,10 @@ static int live_hwsp_rollover_user(void *arg)
if (!tl->has_initial_breadcrumb) if (!tl->has_initial_breadcrumb)
goto out; goto out;
err = intel_context_pin(ce);
if (err)
goto out;
tl->seqno = -4u; tl->seqno = -4u;
WRITE_ONCE(*(u32 *)tl->hwsp_seqno, tl->seqno); WRITE_ONCE(*(u32 *)tl->hwsp_seqno, tl->seqno);
...@@ -1268,7 +1268,7 @@ static int live_hwsp_rollover_user(void *arg) ...@@ -1268,7 +1268,7 @@ static int live_hwsp_rollover_user(void *arg)
this = intel_context_create_request(ce); this = intel_context_create_request(ce);
if (IS_ERR(this)) { if (IS_ERR(this)) {
err = PTR_ERR(this); err = PTR_ERR(this);
goto out; goto out_unpin;
} }
pr_debug("%s: create fence.seqnp:%d\n", pr_debug("%s: create fence.seqnp:%d\n",
...@@ -1287,17 +1287,18 @@ static int live_hwsp_rollover_user(void *arg) ...@@ -1287,17 +1287,18 @@ static int live_hwsp_rollover_user(void *arg)
if (i915_request_wait(rq[2], 0, HZ / 5) < 0) { if (i915_request_wait(rq[2], 0, HZ / 5) < 0) {
pr_err("Wait for timeline wrap timed out!\n"); pr_err("Wait for timeline wrap timed out!\n");
err = -EIO; err = -EIO;
goto out; goto out_unpin;
} }
for (i = 0; i < ARRAY_SIZE(rq); i++) { for (i = 0; i < ARRAY_SIZE(rq); i++) {
if (!i915_request_completed(rq[i])) { if (!i915_request_completed(rq[i])) {
pr_err("Pre-wrap request not completed!\n"); pr_err("Pre-wrap request not completed!\n");
err = -EINVAL; err = -EINVAL;
goto out; goto out_unpin;
} }
} }
out_unpin:
intel_context_unpin(ce);
out: out:
for (i = 0; i < ARRAY_SIZE(rq); i++) for (i = 0; i < ARRAY_SIZE(rq); i++)
i915_request_put(rq[i]); i915_request_put(rq[i]);
...@@ -1339,13 +1340,13 @@ static int live_hwsp_recycle(void *arg) ...@@ -1339,13 +1340,13 @@ static int live_hwsp_recycle(void *arg)
struct intel_timeline *tl; struct intel_timeline *tl;
struct i915_request *rq; struct i915_request *rq;
tl = checked_intel_timeline_create(gt); tl = intel_timeline_create(gt);
if (IS_ERR(tl)) { if (IS_ERR(tl)) {
err = PTR_ERR(tl); err = PTR_ERR(tl);
break; break;
} }
rq = tl_write(tl, engine, count); rq = checked_tl_write(tl, engine, count);
if (IS_ERR(rq)) { if (IS_ERR(rq)) {
intel_timeline_put(tl); intel_timeline_put(tl);
err = PTR_ERR(rq); err = PTR_ERR(rq);
......
...@@ -107,6 +107,7 @@ int __i915_subtests(const char *caller, ...@@ -107,6 +107,7 @@ int __i915_subtests(const char *caller,
#define I915_SELFTEST_DECLARE(x) x #define I915_SELFTEST_DECLARE(x) x
#define I915_SELFTEST_ONLY(x) unlikely(x) #define I915_SELFTEST_ONLY(x) unlikely(x)
#define I915_SELFTEST_EXPORT
#else /* !IS_ENABLED(CONFIG_DRM_I915_SELFTEST) */ #else /* !IS_ENABLED(CONFIG_DRM_I915_SELFTEST) */
...@@ -116,6 +117,7 @@ static inline int i915_perf_selftests(struct pci_dev *pdev) { return 0; } ...@@ -116,6 +117,7 @@ static inline int i915_perf_selftests(struct pci_dev *pdev) { return 0; }
#define I915_SELFTEST_DECLARE(x) #define I915_SELFTEST_DECLARE(x)
#define I915_SELFTEST_ONLY(x) 0 #define I915_SELFTEST_ONLY(x) 0
#define I915_SELFTEST_EXPORT static
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment