Message ID | 20180115204348.8480-1-chris@chris-wilson.co.uk (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 15/01/2018 20:43, Chris Wilson wrote: > Check that we can successfully wait upon a dma_fence using the > i915_sw_fence, including the optional timeout mechanism. > > v2: Account for the rounding up of the timeout to the next second. > Unfortunately, the minimum delay is then 1 second. > > Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> > Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> > --- > drivers/gpu/drm/i915/selftests/i915_sw_fence.c | 137 +++++++++++++++++++++++++ > 1 file changed, 137 insertions(+) > > diff --git a/drivers/gpu/drm/i915/selftests/i915_sw_fence.c b/drivers/gpu/drm/i915/selftests/i915_sw_fence.c > index ea01d0fe3ace..b51319677110 100644 > --- a/drivers/gpu/drm/i915/selftests/i915_sw_fence.c > +++ b/drivers/gpu/drm/i915/selftests/i915_sw_fence.c > @@ -27,6 +27,7 @@ > #include <linux/prime_numbers.h> > > #include "../i915_selftest.h" > +#include "../i915_utils.h" > > static int __i915_sw_fence_call > fence_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state) > @@ -606,6 +607,141 @@ static int test_timer(void *arg) > return -EINVAL; > } > > +static const char *mock_name(struct dma_fence *fence) > +{ > + return "mock"; > +} > + > +static bool mock_enable_signaling(struct dma_fence *fence) > +{ > + return true; > +} > + > +static const struct dma_fence_ops mock_fence_ops = { > + .get_driver_name = mock_name, > + .get_timeline_name = mock_name, > + .enable_signaling = mock_enable_signaling, > + .wait = dma_fence_default_wait, > + .release = dma_fence_free, > +}; > + > +static DEFINE_SPINLOCK(mock_fence_lock); > + > +static struct dma_fence *alloc_dma_fence(void) > +{ > + struct dma_fence *dma; > + > + dma = kmalloc(sizeof(*dma), GFP_KERNEL); > + if (dma) > + dma_fence_init(dma, &mock_fence_ops, &mock_fence_lock, 0, 0); > + > + return dma; > +} > + > +static struct i915_sw_fence * > +wrap_dma_fence(struct dma_fence *dma, unsigned long delay) await_dma_fence? > +{ > + struct i915_sw_fence *fence; > + int err; > + > + fence = alloc_fence(); > + if (!fence) > + return ERR_PTR(-ENOMEM); > + > + err = i915_sw_fence_await_dma_fence(fence, dma, delay, GFP_NOWAIT); > + i915_sw_fence_commit(fence); > + if (err < 0) { > + free_fence(fence); > + return ERR_PTR(err); > + } > + > + return fence; > +} > + > +static int test_dma_fence(void *arg) > +{ > + struct i915_sw_fence *timeout = NULL, *not = NULL; > + unsigned long delay = i915_selftest.timeout_jiffies; > + unsigned long end, sleep; > + struct dma_fence *dma; > + int err; > + > + dma = alloc_dma_fence(); > + if (!dma) > + return -ENOMEM; > + > + timeout = wrap_dma_fence(dma, delay); > + if (IS_ERR(timeout)) { > + err = PTR_ERR(timeout); > + goto err; > + } > + > + not = wrap_dma_fence(dma, 0); > + if (IS_ERR(not)) { > + err = PTR_ERR(not); > + goto err; > + } > + > + err = -EINVAL; > + if (i915_sw_fence_done(timeout) || i915_sw_fence_done(not)) { > + pr_err("Fences immediately signaled\n"); > + goto err; > + } > + > + /* We round the timeout for the fence up to the next second */ > + end = round_jiffies_up(jiffies + delay); > + > + sleep = jiffies_to_usecs(delay) / 3; > + usleep_range(sleep, 2 * sleep); > + if (time_after(jiffies, end)) { > + pr_debug("Slept too long, delay=%lu, skipping!\n", delay); > + goto skip; > + } > + > + if (i915_sw_fence_done(timeout) || i915_sw_fence_done(not)) { > + pr_err("Fences signaled too early\n"); > + goto err; > + } > + > + do { > + sleep = jiffies_to_usecs(end - jiffies + 1); > + usleep_range(sleep, 2 * sleep); > + } while (!time_after(jiffies, end)); > + > + if (i915_sw_fence_done(not)) { > + pr_err("No tiemout fence signaled!\n"); > + goto err; > + } > + > + if (!i915_sw_fence_done(timeout)) { > + pr_err("Timeout fence unsignaled!\n"); > + goto err; > + } > + > +skip: > + dma_fence_signal(dma); > + > + if (!i915_sw_fence_done(timeout) || !i915_sw_fence_done(not)) { > + pr_err("Fences unsignaled\n"); > + goto err; > + } > + > + free_fence(fetch_and_zero(¬)); > + free_fence(fetch_and_zero(&timeout)); A bit of an overkill with fetch_and_zero. > + dma_fence_put(dma); > + > + return 0; > + > +err: > + dma_fence_signal(dma); > + if (!IS_ERR_OR_NULL(timeout)) > + free_fence(timeout); > + if (!IS_ERR_OR_NULL(not)) > + free_fence(not); > + dma_fence_put(dma); > + return err; > +} > + > int i915_sw_fence_mock_selftests(void) > { > static const struct i915_subtest tests[] = { > @@ -618,6 +754,7 @@ int i915_sw_fence_mock_selftests(void) > SUBTEST(test_chain), > SUBTEST(test_ipc), > SUBTEST(test_timer), > + SUBTEST(test_dma_fence), > }; > > return i915_subtests(tests, NULL); > Looks OK anyway. Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Regards, Tvrtko
Quoting Tvrtko Ursulin (2018-01-16 09:48:48) > > On 15/01/2018 20:43, Chris Wilson wrote: > > +static struct dma_fence *alloc_dma_fence(void) > > +{ > > + struct dma_fence *dma; > > + > > + dma = kmalloc(sizeof(*dma), GFP_KERNEL); > > + if (dma) > > + dma_fence_init(dma, &mock_fence_ops, &mock_fence_lock, 0, 0); > > + > > + return dma; > > +} > > + > > +static struct i915_sw_fence * > > +wrap_dma_fence(struct dma_fence *dma, unsigned long delay) > > await_dma_fence? Hmm, but no, I think I prefer having the distinction that this is creating a i915_sw_fence rather than attaching it to an existing fence, which is what the await routines do. [snip] > > +skip: > > + dma_fence_signal(dma); > > + > > + if (!i915_sw_fence_done(timeout) || !i915_sw_fence_done(not)) { > > + pr_err("Fences unsignaled\n"); > > + goto err; > > + } > > + > > + free_fence(fetch_and_zero(¬)); > > + free_fence(fetch_and_zero(&timeout)); > > A bit of an overkill with fetch_and_zero. 'Twas forgotten leftovers. > > + dma_fence_put(dma); > > + > > + return 0; > > + > > +err: > > + dma_fence_signal(dma); > > + if (!IS_ERR_OR_NULL(timeout)) > > + free_fence(timeout); > > + if (!IS_ERR_OR_NULL(not)) > > + free_fence(not); > > + dma_fence_put(dma); > > + return err; > > +} > > + > > int i915_sw_fence_mock_selftests(void) > > { > > static const struct i915_subtest tests[] = { > > @@ -618,6 +754,7 @@ int i915_sw_fence_mock_selftests(void) > > SUBTEST(test_chain), > > SUBTEST(test_ipc), > > SUBTEST(test_timer), > > + SUBTEST(test_dma_fence), > > }; > > > > return i915_subtests(tests, NULL); > > > > Looks OK anyway. > > Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Ta, -Chris
Quoting Tvrtko Ursulin (2018-01-16 09:48:48) > > On 15/01/2018 20:43, Chris Wilson wrote: > > Check that we can successfully wait upon a dma_fence using the > > i915_sw_fence, including the optional timeout mechanism. > > > > v2: Account for the rounding up of the timeout to the next second. > > Unfortunately, the minimum delay is then 1 second. > > > > Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> > > Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> > > --- > Looks OK anyway. > > Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Fixed up the overkill, and pushed. Thanks for the suggestion and reviewing, (Also included the comment rewrite in the push as a bonus.) -Chris
diff --git a/drivers/gpu/drm/i915/selftests/i915_sw_fence.c b/drivers/gpu/drm/i915/selftests/i915_sw_fence.c index ea01d0fe3ace..b51319677110 100644 --- a/drivers/gpu/drm/i915/selftests/i915_sw_fence.c +++ b/drivers/gpu/drm/i915/selftests/i915_sw_fence.c @@ -27,6 +27,7 @@ #include <linux/prime_numbers.h> #include "../i915_selftest.h" +#include "../i915_utils.h" static int __i915_sw_fence_call fence_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state) @@ -606,6 +607,141 @@ static int test_timer(void *arg) return -EINVAL; } +static const char *mock_name(struct dma_fence *fence) +{ + return "mock"; +} + +static bool mock_enable_signaling(struct dma_fence *fence) +{ + return true; +} + +static const struct dma_fence_ops mock_fence_ops = { + .get_driver_name = mock_name, + .get_timeline_name = mock_name, + .enable_signaling = mock_enable_signaling, + .wait = dma_fence_default_wait, + .release = dma_fence_free, +}; + +static DEFINE_SPINLOCK(mock_fence_lock); + +static struct dma_fence *alloc_dma_fence(void) +{ + struct dma_fence *dma; + + dma = kmalloc(sizeof(*dma), GFP_KERNEL); + if (dma) + dma_fence_init(dma, &mock_fence_ops, &mock_fence_lock, 0, 0); + + return dma; +} + +static struct i915_sw_fence * +wrap_dma_fence(struct dma_fence *dma, unsigned long delay) +{ + struct i915_sw_fence *fence; + int err; + + fence = alloc_fence(); + if (!fence) + return ERR_PTR(-ENOMEM); + + err = i915_sw_fence_await_dma_fence(fence, dma, delay, GFP_NOWAIT); + i915_sw_fence_commit(fence); + if (err < 0) { + free_fence(fence); + return ERR_PTR(err); + } + + return fence; +} + +static int test_dma_fence(void *arg) +{ + struct i915_sw_fence *timeout = NULL, *not = NULL; + unsigned long delay = i915_selftest.timeout_jiffies; + unsigned long end, sleep; + struct dma_fence *dma; + int err; + + dma = alloc_dma_fence(); + if (!dma) + return -ENOMEM; + + timeout = wrap_dma_fence(dma, delay); + if (IS_ERR(timeout)) { + err = PTR_ERR(timeout); + goto err; + } + + not = wrap_dma_fence(dma, 0); + if (IS_ERR(not)) { + err = PTR_ERR(not); + goto err; + } + + err = -EINVAL; + if (i915_sw_fence_done(timeout) || i915_sw_fence_done(not)) { + pr_err("Fences immediately signaled\n"); + goto err; + } + + /* We round the timeout for the fence up to the next second */ + end = round_jiffies_up(jiffies + delay); + + sleep = jiffies_to_usecs(delay) / 3; + usleep_range(sleep, 2 * sleep); + if (time_after(jiffies, end)) { + pr_debug("Slept too long, delay=%lu, skipping!\n", delay); + goto skip; + } + + if (i915_sw_fence_done(timeout) || i915_sw_fence_done(not)) { + pr_err("Fences signaled too early\n"); + goto err; + } + + do { + sleep = jiffies_to_usecs(end - jiffies + 1); + usleep_range(sleep, 2 * sleep); + } while (!time_after(jiffies, end)); + + if (i915_sw_fence_done(not)) { + pr_err("No tiemout fence signaled!\n"); + goto err; + } + + if (!i915_sw_fence_done(timeout)) { + pr_err("Timeout fence unsignaled!\n"); + goto err; + } + +skip: + dma_fence_signal(dma); + + if (!i915_sw_fence_done(timeout) || !i915_sw_fence_done(not)) { + pr_err("Fences unsignaled\n"); + goto err; + } + + free_fence(fetch_and_zero(¬)); + free_fence(fetch_and_zero(&timeout)); + dma_fence_put(dma); + + return 0; + +err: + dma_fence_signal(dma); + if (!IS_ERR_OR_NULL(timeout)) + free_fence(timeout); + if (!IS_ERR_OR_NULL(not)) + free_fence(not); + dma_fence_put(dma); + return err; +} + int i915_sw_fence_mock_selftests(void) { static const struct i915_subtest tests[] = { @@ -618,6 +754,7 @@ int i915_sw_fence_mock_selftests(void) SUBTEST(test_chain), SUBTEST(test_ipc), SUBTEST(test_timer), + SUBTEST(test_dma_fence), }; return i915_subtests(tests, NULL);
Check that we can successfully wait upon a dma_fence using the i915_sw_fence, including the optional timeout mechanism. v2: Account for the rounding up of the timeout to the next second. Unfortunately, the minimum delay is then 1 second. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> --- drivers/gpu/drm/i915/selftests/i915_sw_fence.c | 137 +++++++++++++++++++++++++ 1 file changed, 137 insertions(+)