All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jason Ekstrand <jason@jlekstrand.net>
To: IGT GPU Tools <igt-dev@lists.freedesktop.org>
Subject: Re: [igt-dev] [i-g-t] lib/ioctl_wrappers: Keep IGT working without pread/pwrite ioctls
Date: Thu, 11 Mar 2021 14:47:41 -0600	[thread overview]
Message-ID: <CAOFGe96q2QR8zm3UgUYGRcz_1C0H=yUe2S=5FNmR4V0tqCZU0g@mail.gmail.com> (raw)

Sorry for breaking the reply thread but I just subscribed to the I-G-T
mailing list today.  Shouldn't be a problem going forward.

Ashutosh Dixit <ashutosh.dixit@intel.com> wrote:
> The general direction at this time is to phase out pread/write ioctls
> and not support them in future products. This means IGT must handle
> the absence of these ioctls. This patch does this by modifying
> gem_read() and gem_write() to do the read/write using the pread/pwrite
> ioctls first but when these ioctls are unavailable fall back to doing
> the read/write using a combination of mmap and memcpy.
>
> Callers who must absolutely use the pread/pwrite ioctls (such as tests
> which test these ioctls or must otherwise only use the pread/pwrite
> ioctls) must use gem_require_pread_pwrite() to skip when these ioctls
> are not available.
>
> v1: Removed __gem_pread, gem_pread, __gem_pwrite and gem_pwrite
>     introduced previously since they are not necessary,
>     gem_require_pread_pwrite is sufficient
> v2: Fix CI failures in gem_advise and gen9_exec_parse by introducing
>     gem_require_pread_pwrite
> v3: Skip mmap for 0 length read/write's
> v4: Remove redundant igt_assert's
> v5: Re-run
> v6: s/EOPNOTSUPP/-EOPNOTSUPP/
> v7: Rebase on latest master, skip gem_exec_parallel@userptr with
>     gem_require_pread_pwrite
>
> Reviewed-by: Zbigniew Kempczyński <zbigniew.kempczynski@intel.com>
> Signed-off-by: Ashutosh Dixit <ashutosh.dixit@intel.com>
> ---
>  lib/ioctl_wrappers.c                        | 135 +++++++++++++++++++-
>  lib/ioctl_wrappers.h                        |   3 +
>  tests/i915/gem_exec_parallel.c              |   3 +
>  tests/i915/gem_madvise.c                    |   2 +
>  tests/i915/gem_partial_pwrite_pread.c       |   1 +
>  tests/i915/gem_pread.c                      |   1 +
>  tests/i915/gem_pread_after_blit.c           |   1 +
>  tests/i915/gem_pwrite.c                     |   1 +
>  tests/i915/gem_pwrite_snooped.c             |   1 +
>  tests/i915/gem_readwrite.c                  |   1 +
>  tests/i915/gem_set_tiling_vs_pwrite.c       |   1 +
>  tests/i915/gem_tiled_partial_pwrite_pread.c |   1 +
>  tests/i915/gem_tiled_pread_basic.c          |   1 +
>  tests/i915/gem_tiled_pread_pwrite.c         |   1 +
>  tests/i915/gem_userptr_blits.c              |   2 +
>  tests/i915/gen9_exec_parse.c                |   4 +-
>  16 files changed, 152 insertions(+), 7 deletions(-)
>
> diff --git a/lib/ioctl_wrappers.c b/lib/ioctl_wrappers.c
> index 45415621b7..4440004c42 100644
> --- a/lib/ioctl_wrappers.c
> +++ b/lib/ioctl_wrappers.c
> @@ -56,6 +56,7 @@
>  #include "igt_debugfs.h"
>  #include "igt_sysfs.h"
>  #include "config.h"
> +#include "i915/gem_mman.h"
>
>  #ifdef HAVE_VALGRIND
>  #include <valgrind/valgrind.h>
> @@ -324,6 +325,70 @@ void gem_close(int fd, uint32_t handle)
>      do_ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close_bo);
>  }
>
> +static bool is_cache_coherent(int fd, uint32_t handle)
> +{
> +    return gem_get_caching(fd, handle) != I915_CACHING_NONE;
> +}
> +
> +static void mmap_write(int fd, uint32_t handle, uint64_t offset,
> +               const void *buf, uint64_t length)
> +{
> +    void *map = NULL;
> +
> +    if (!length)
> +        return;
> +
> +    if (is_cache_coherent(fd, handle)) {
> +        /* offset arg for mmap functions must be 0 */
> +        map = __gem_mmap__cpu_coherent(fd, handle, 0, offset + length,
> +                           PROT_READ | PROT_WRITE);
> +        if (map)
> +            gem_set_domain(fd, handle,
> +                       I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);

Not sure how much it matters for IGT but the pread/pwrite ioctls
appear to always leave the BO in the GTT domain.

Otherwise, everything here looks pretty sane.

--Jason

> +    }
> +
> +    if (!map) {
> +        map = __gem_mmap_offset__wc(fd, handle, 0, offset + length,
> +                        PROT_READ | PROT_WRITE);
> +        if (!map)
> +            map = gem_mmap__wc(fd, handle, 0, offset + length,
> +                       PROT_READ | PROT_WRITE);
> +        gem_set_domain(fd, handle,
> +                   I915_GEM_DOMAIN_WC, I915_GEM_DOMAIN_WC);
> +    }
> +
> +    memcpy(map + offset, buf, length);
> +    munmap(map, offset + length);
> +}
> +
> +static void mmap_read(int fd, uint32_t handle, uint64_t offset, void *buf, uint64_t length)
> +{
> +    void *map = NULL;
> +
> +    if (!length)
> +        return;
> +
> +    if (gem_has_llc(fd) || is_cache_coherent(fd, handle)) {
> +        /* offset arg for mmap functions must be 0 */
> +        map = __gem_mmap__cpu_coherent(fd, handle, 0,
> +                           offset + length, PROT_READ);
> +        if (map)
> +            gem_set_domain(fd, handle, I915_GEM_DOMAIN_CPU, 0);
> +    }
> +
> +    if (!map) {
> +        map = __gem_mmap_offset__wc(fd, handle, 0, offset + length,
> +                        PROT_READ);
> +        if (!map)
> +            map = gem_mmap__wc(fd, handle, 0, offset + length,
> +                       PROT_READ);
> +        gem_set_domain(fd, handle, I915_GEM_DOMAIN_WC, 0);
> +    }
> +
> +    memcpy(buf, map + offset, length);
> +    munmap(map, offset + length);
> +}
> +
>  int __gem_write(int fd, uint32_t handle, uint64_t offset, const void *buf, uint64_t length)
>  {
>      struct drm_i915_gem_pwrite gem_pwrite;
> @@ -349,12 +414,18 @@ int __gem_write(int fd, uint32_t handle, uint64_t offset, const void *buf, uint6
>   * @buf: pointer to the data to write into the buffer
>   * @length: size of the subrange
>   *
> - * This wraps the PWRITE ioctl, which is to upload a linear data to a subrange
> - * of a gem buffer object.
> + * Method to write to a gem object. Uses the PWRITE ioctl when it is
> + * available, else it uses mmap + memcpy to upload linear data to a
> + * subrange of a gem buffer object.
>   */
>  void gem_write(int fd, uint32_t handle, uint64_t offset, const void *buf, uint64_t length)
>  {
> -    igt_assert_eq(__gem_write(fd, handle, offset, buf, length), 0);
> +    int ret = __gem_write(fd, handle, offset, buf, length);
> +
> +    igt_assert(ret == 0 || ret == -EOPNOTSUPP);
> +
> +    if (ret == -EOPNOTSUPP)
> +        mmap_write(fd, handle, offset, buf, length);
>  }
>
>  int __gem_read(int fd, uint32_t handle, uint64_t offset, void *buf, uint64_t length)
> @@ -381,12 +452,64 @@ int __gem_read(int fd, uint32_t handle, uint64_t offset, void *buf, uint64_t len
>   * @buf: pointer to the data to read into
>   * @length: size of the subrange
>   *
> - * This wraps the PREAD ioctl, which is to download a linear data to a subrange
> - * of a gem buffer object.
> + * Method to read from a gem object. Uses the PREAD ioctl when it is
> + * available, else it uses mmap + memcpy to download linear data from a
> + * subrange of a gem buffer object.
>   */
>  void gem_read(int fd, uint32_t handle, uint64_t offset, void *buf, uint64_t length)
>  {
> -    igt_assert_eq(__gem_read(fd, handle, offset, buf, length), 0);
> +    int ret = __gem_read(fd, handle, offset, buf, length);
> +
> +    igt_assert(ret == 0 || ret == -EOPNOTSUPP);
> +
> +    if (ret == -EOPNOTSUPP)
> +        mmap_read(fd, handle, offset, buf, length);
> +}
> +
> +/**
> + * gem_has_pwrite
> + * @fd: open i915 drm file descriptor
> + *
> + * Feature test macro to query whether pwrite ioctl is supported
> + */
> +bool gem_has_pwrite(int fd)
> +{
> +    uint32_t handle = gem_create(fd, 4096);
> +    int buf, ret;
> +
> +    ret = __gem_write(fd, handle, 0, &buf, sizeof(buf));
> +    gem_close(fd, handle);
> +
> +    return ret != -EOPNOTSUPP;
> +}
> +
> +/**
> + * gem_has_pread
> + * @fd: open i915 drm file descriptor
> + *
> + * Feature test macro to query whether pread ioctl is supported
> + */
> +bool gem_has_pread(int fd)
> +{
> +    uint32_t handle = gem_create(fd, 4096);
> +    int buf, ret;
> +
> +    ret = __gem_read(fd, handle, 0, &buf, sizeof(buf));
> +    gem_close(fd, handle);
> +
> +    return ret != -EOPNOTSUPP;
> +}
> +
> +/**
> + * gem_require_pread_pwrite
> + * @fd: open i915 drm file descriptor
> + *
> + * Feature test macro to query whether pread/pwrite ioctls are supported
> + * and skip if they are not
> + */
> +void gem_require_pread_pwrite(int fd)
> +{
> +    igt_require(gem_has_pread(fd) && gem_has_pwrite(fd));
>  }
>
>  int __gem_set_domain(int fd, uint32_t handle, uint32_t read, uint32_t write)
> diff --git a/lib/ioctl_wrappers.h b/lib/ioctl_wrappers.h
> index 69e198419c..9ea673653e 100644
> --- a/lib/ioctl_wrappers.h
> +++ b/lib/ioctl_wrappers.h
> @@ -71,6 +71,9 @@ int __gem_write(int fd, uint32_t handle, uint64_t offset, const void *buf, uint6
>  void gem_write(int fd, uint32_t handle, uint64_t offset,  const void *buf, uint64_t length);
>  int __gem_read(int fd, uint32_t handle, uint64_t offset, void *buf, uint64_t length);
>  void gem_read(int fd, uint32_t handle, uint64_t offset, void *buf, uint64_t length);
> +bool gem_has_pwrite(int fd);
> +bool gem_has_pread(int fd);
> +void gem_require_pread_pwrite(int fd);
>  int __gem_set_domain(int fd, uint32_t handle, uint32_t read, uint32_t write);
>  void gem_set_domain(int fd, uint32_t handle, uint32_t read, uint32_t write);
>  int gem_wait(int fd, uint32_t handle, int64_t *timeout_ns);
> diff --git a/tests/i915/gem_exec_parallel.c b/tests/i915/gem_exec_parallel.c
> index d3dd06a654..a0469a6438 100644
> --- a/tests/i915/gem_exec_parallel.c
> +++ b/tests/i915/gem_exec_parallel.c
> @@ -204,6 +204,9 @@ static void all(int fd, struct intel_execution_engine2 *engine, unsigned flags)
>      if (flags & CONTEXTS)
>          gem_require_contexts(fd);
>
> +    if (flags & USERPTR)
> +        gem_require_pread_pwrite(fd);
> +
>      if (flags & FDS) {
>          igt_require(gen > 5);
>          igt_require(igt_allow_unlimited_files());
> diff --git a/tests/i915/gem_madvise.c b/tests/i915/gem_madvise.c
> index 623c8b0913..f85c351857 100644
> --- a/tests/i915/gem_madvise.c
> +++ b/tests/i915/gem_madvise.c
> @@ -155,6 +155,7 @@ dontneed_before_pwrite(void)
>      uint32_t bbe = MI_BATCH_BUFFER_END;
>      uint32_t handle;
>
> +    gem_require_pread_pwrite(fd);
>      handle = gem_create(fd, OBJECT_SIZE);
>      gem_madvise(fd, handle, I915_MADV_DONTNEED);
>
> @@ -171,6 +172,7 @@ dontneed_before_exec(void)
>      struct drm_i915_gem_exec_object2 exec;
>      uint32_t buf[] = { MI_BATCH_BUFFER_END, 0 };
>
> +    gem_require_pread_pwrite(fd);
>      memset(&execbuf, 0, sizeof(execbuf));
>      memset(&exec, 0, sizeof(exec));
>
> diff --git a/tests/i915/gem_partial_pwrite_pread.c b/tests/i915/gem_partial_pwrite_pread.c
> index 72c33539d3..5a14d424b2 100644
> --- a/tests/i915/gem_partial_pwrite_pread.c
> +++ b/tests/i915/gem_partial_pwrite_pread.c
> @@ -284,6 +284,7 @@ igt_main
>          data.drm_fd = drm_open_driver(DRIVER_INTEL);
>          igt_require_gem(data.drm_fd);
>          gem_require_blitter(data.drm_fd);
> +        gem_require_pread_pwrite(data.drm_fd);
>
>          data.devid = intel_get_drm_devid(data.drm_fd);
>          data.bops = buf_ops_create(data.drm_fd);
> diff --git a/tests/i915/gem_pread.c b/tests/i915/gem_pread.c
> index 0c4ec0d2fe..ec9991eebd 100644
> --- a/tests/i915/gem_pread.c
> +++ b/tests/i915/gem_pread.c
> @@ -300,6 +300,7 @@ igt_main_args("s:", NULL, help_str, opt_handler, NULL)
>
>      igt_fixture {
>          fd = drm_open_driver(DRIVER_INTEL);
> +        gem_require_pread_pwrite(fd);
>
>          dst = gem_create(fd, object_size);
>          src = malloc(object_size);
> diff --git a/tests/i915/gem_pread_after_blit.c b/tests/i915/gem_pread_after_blit.c
> index f5eba0d50a..3b56f787aa 100644
> --- a/tests/i915/gem_pread_after_blit.c
> +++ b/tests/i915/gem_pread_after_blit.c
> @@ -216,6 +216,7 @@ igt_main
>      igt_fixture {
>          fd = drm_open_driver(DRIVER_INTEL);
>          igt_require_gem(fd);
> +        gem_require_pread_pwrite(fd);
>
>          bops = buf_ops_create(fd);
>
> diff --git a/tests/i915/gem_pwrite.c b/tests/i915/gem_pwrite.c
> index 98bec55821..5fd15e6a8f 100644
> --- a/tests/i915/gem_pwrite.c
> +++ b/tests/i915/gem_pwrite.c
> @@ -488,6 +488,7 @@ igt_main_args("s:", NULL, help_str, opt_handler, NULL)
>
>      igt_fixture {
>          fd = drm_open_driver(DRIVER_INTEL);
> +        gem_require_pread_pwrite(fd);
>
>          dst = gem_create(fd, object_size);
>          src = malloc(object_size);
> diff --git a/tests/i915/gem_pwrite_snooped.c b/tests/i915/gem_pwrite_snooped.c
> index 52ebaec2f2..e6a10747d5 100644
> --- a/tests/i915/gem_pwrite_snooped.c
> +++ b/tests/i915/gem_pwrite_snooped.c
> @@ -133,6 +133,7 @@ igt_simple_main
>      fd = drm_open_driver(DRIVER_INTEL);
>      igt_require_gem(fd);
>      gem_require_blitter(fd);
> +    gem_require_pread_pwrite(fd);
>
>      bops = buf_ops_create(fd);
>
> diff --git a/tests/i915/gem_readwrite.c b/tests/i915/gem_readwrite.c
> index d675810ef2..8a958cc904 100644
> --- a/tests/i915/gem_readwrite.c
> +++ b/tests/i915/gem_readwrite.c
> @@ -85,6 +85,7 @@ igt_main
>
>      igt_fixture {
>          fd = drm_open_driver(DRIVER_INTEL);
> +        gem_require_pread_pwrite(fd);
>
>          handle = gem_create(fd, OBJECT_SIZE);
>      }
> diff --git a/tests/i915/gem_set_tiling_vs_pwrite.c b/tests/i915/gem_set_tiling_vs_pwrite.c
> index 771dd2e136..87909d3c7c 100644
> --- a/tests/i915/gem_set_tiling_vs_pwrite.c
> +++ b/tests/i915/gem_set_tiling_vs_pwrite.c
> @@ -57,6 +57,7 @@ igt_simple_main
>
>      fd = drm_open_driver(DRIVER_INTEL);
>      igt_require(gem_available_fences(fd) > 0);
> +    gem_require_pread_pwrite(fd);
>
>      for (int i = 0; i < OBJECT_SIZE/4; i++)
>          data[i] = i;
> diff --git a/tests/i915/gem_tiled_partial_pwrite_pread.c b/tests/i915/gem_tiled_partial_pwrite_pread.c
> index 4f8f4190b5..95fb69c659 100644
> --- a/tests/i915/gem_tiled_partial_pwrite_pread.c
> +++ b/tests/i915/gem_tiled_partial_pwrite_pread.c
> @@ -280,6 +280,7 @@ igt_main
>          igt_require_gem(fd);
>          gem_require_mappable_ggtt(fd);
>          gem_require_blitter(fd);
> +        gem_require_pread_pwrite(fd);
>
>          bops = buf_ops_create(fd);
>
> diff --git a/tests/i915/gem_tiled_pread_basic.c b/tests/i915/gem_tiled_pread_basic.c
> index 862714140a..186f630f7d 100644
> --- a/tests/i915/gem_tiled_pread_basic.c
> +++ b/tests/i915/gem_tiled_pread_basic.c
> @@ -128,6 +128,7 @@ igt_simple_main
>      igt_require(gem_available_fences(fd) > 0);
>      handle = create_bo(fd);
>      igt_require(gem_get_tiling(fd, handle, &tiling, &swizzle));
> +    gem_require_pread_pwrite(fd);
>
>      devid = intel_get_drm_devid(fd);
>
> diff --git a/tests/i915/gem_tiled_pread_pwrite.c b/tests/i915/gem_tiled_pread_pwrite.c
> index b73fa12626..ef1e1b3c3c 100644
> --- a/tests/i915/gem_tiled_pread_pwrite.c
> +++ b/tests/i915/gem_tiled_pread_pwrite.c
> @@ -114,6 +114,7 @@ igt_simple_main
>
>      fd = drm_open_driver(DRIVER_INTEL);
>      igt_require(gem_available_fences(fd) > 0);
> +    gem_require_pread_pwrite(fd);
>
>      count = gem_available_fences(fd) + 1;
>      intel_require_memory(2 * count, sizeof(linear), CHECK_RAM);
> diff --git a/tests/i915/gem_userptr_blits.c b/tests/i915/gem_userptr_blits.c
> index 8765123e09..ded761a550 100644
> --- a/tests/i915/gem_userptr_blits.c
> +++ b/tests/i915/gem_userptr_blits.c
> @@ -1137,6 +1137,7 @@ static int test_forbidden_ops(int fd)
>      uint32_t handle;
>      void *ptr;
>
> +    gem_require_pread_pwrite(fd);
>      igt_assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
>      gem_userptr(fd, ptr, PAGE_SIZE, 0, userptr_flags, &handle);
>
> @@ -1664,6 +1665,7 @@ static void test_readonly_pwrite(int i915)
>       */
>
>      igt_require(igt_setup_clflush());
> +    gem_require_pread_pwrite(i915);
>
>      sz = 16 << 12;
>      pages = mmap(NULL, sz, PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
> diff --git a/tests/i915/gen9_exec_parse.c b/tests/i915/gen9_exec_parse.c
> index 6f54c4e133..f9de90d2cf 100644
> --- a/tests/i915/gen9_exec_parse.c
> +++ b/tests/i915/gen9_exec_parse.c
> @@ -1235,8 +1235,10 @@ igt_main
>                 -EINVAL);
>      }
>
> -    igt_subtest("batch-invalid-length")
> +    igt_subtest("batch-invalid-length") {
> +        gem_require_pread_pwrite(i915);
>          test_invalid_length(i915, handle);
> +    }
>
>      igt_subtest("basic-rejected")
>          test_rejected(i915, handle, false);
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

             reply	other threads:[~2021-03-11 20:47 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-11 20:47 Jason Ekstrand [this message]
2021-03-11 21:02 ` [igt-dev] [i-g-t] lib/ioctl_wrappers: Keep IGT working without pread/pwrite ioctls Dixit, Ashutosh
2021-03-11 21:06   ` Jason Ekstrand
  -- strict thread matches above, loose matches on Subject: below --
2020-09-30  3:40 [igt-dev] [PATCH i-g-t] " Ashutosh Dixit
2021-01-11 20:46 ` [igt-dev] [i-g-t] " Dave Airlie

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAOFGe96q2QR8zm3UgUYGRcz_1C0H=yUe2S=5FNmR4V0tqCZU0g@mail.gmail.com' \
    --to=jason@jlekstrand.net \
    --cc=igt-dev@lists.freedesktop.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.