[PATCH 06/30] drm/i915: Rework struct phys attachment handling
Maarten Lankhorst
maarten.lankhorst at linux.intel.com
Fri Sep 11 12:21:25 UTC 2020
Instead of creating a separate object type, we make changes to
the shmem type, to clear struct page backing. This will allow us to
ensure we never run into a race when we exchange obj->ops with other
function pointers.
Signed-off-by: Maarten Lankhorst <maarten.lankhorst at linux.intel.com>
---
drivers/gpu/drm/i915/gem/i915_gem_object.h | 3 +
drivers/gpu/drm/i915/gem/i915_gem_phys.c | 89 ++++++++++---------
drivers/gpu/drm/i915/gem/i915_gem_shmem.c | 8 +-
.../drm/i915/gem/selftests/i915_gem_phys.c | 8 +-
4 files changed, 63 insertions(+), 45 deletions(-)
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h
index ba93c526128c..d1a01b2ebec2 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h
@@ -38,6 +38,9 @@ void __i915_gem_object_release_shmem(struct drm_i915_gem_object *obj,
bool needs_clflush);
int i915_gem_object_attach_phys(struct drm_i915_gem_object *obj, int align);
+void i915_gem_object_put_pages_phys(struct drm_i915_gem_object *obj,
+ struct sg_table *pages);
+
void i915_gem_close_object(struct drm_gem_object *gem, struct drm_file *file);
void i915_gem_free_object(struct drm_gem_object *obj);
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_phys.c b/drivers/gpu/drm/i915/gem/i915_gem_phys.c
index 28147aab47b9..49db3ef20783 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_phys.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_phys.c
@@ -89,7 +89,7 @@ static int i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj)
return -ENOMEM;
}
-static void
+void
i915_gem_object_put_pages_phys(struct drm_i915_gem_object *obj,
struct sg_table *pages)
{
@@ -134,81 +134,84 @@ i915_gem_object_put_pages_phys(struct drm_i915_gem_object *obj,
vaddr, dma);
}
-static void phys_release(struct drm_i915_gem_object *obj)
+static int i915_gem_object_shmem_to_phys(struct drm_i915_gem_object *obj)
{
- fput(obj->base.filp);
-}
+ struct sg_table *pages;
+ int err;
+
+ pages = __i915_gem_object_unset_pages(obj);
+
+ err = i915_gem_object_get_pages_phys(obj);
+ if (err)
+ goto err_xfer;
-static const struct drm_i915_gem_object_ops i915_gem_phys_ops = {
- .name = "i915_gem_object_phys",
- .get_pages = i915_gem_object_get_pages_phys,
- .put_pages = i915_gem_object_put_pages_phys,
+ /* Perma-pin (until release) the physical set of pages */
+ __i915_gem_object_pin_pages(obj);
- .release = phys_release,
-};
+ if (!IS_ERR_OR_NULL(pages))
+ i915_gem_shmem_ops.put_pages(obj, pages);
+
+ /* We're no longer struct page backed */
+ obj->flags &= ~I915_BO_ALLOC_STRUCT_PAGE;
+ i915_gem_object_release_memory_region(obj);
+ return 0;
+
+err_xfer:
+ if (!IS_ERR_OR_NULL(pages)) {
+ unsigned int sg_page_sizes = i915_sg_page_sizes(pages->sgl);
+
+ __i915_gem_object_set_pages(obj, pages, sg_page_sizes);
+ }
+ return err;
+}
int i915_gem_object_attach_phys(struct drm_i915_gem_object *obj, int align)
{
- struct sg_table *pages;
int err;
if (align > obj->base.size)
return -EINVAL;
- if (obj->ops == &i915_gem_phys_ops)
- return 0;
-
if (obj->ops != &i915_gem_shmem_ops)
return -EINVAL;
+ if (!i915_gem_object_has_struct_page(obj))
+ return 0;
+
err = i915_gem_object_unbind(obj, I915_GEM_OBJECT_UNBIND_ACTIVE);
if (err)
return err;
mutex_lock_nested(&obj->mm.lock, I915_MM_GET_PAGES);
+ if (unlikely(!i915_gem_object_has_struct_page(obj)))
+ goto out;
+
if (obj->mm.madv != I915_MADV_WILLNEED) {
err = -EFAULT;
- goto err_unlock;
+ goto out;
}
if (obj->mm.quirked) {
err = -EFAULT;
- goto err_unlock;
+ goto out;
}
- if (obj->mm.mapping) {
+ if (obj->mm.mapping || i915_gem_object_has_pinned_pages(obj)) {
err = -EBUSY;
- goto err_unlock;
+ goto out;
}
- pages = __i915_gem_object_unset_pages(obj);
-
- obj->ops = &i915_gem_phys_ops;
-
- err = ____i915_gem_object_get_pages(obj);
- if (err)
- goto err_xfer;
-
- /* Perma-pin (until release) the physical set of pages */
- __i915_gem_object_pin_pages(obj);
-
- if (!IS_ERR_OR_NULL(pages))
- i915_gem_shmem_ops.put_pages(obj, pages);
-
- i915_gem_object_release_memory_region(obj);
-
- mutex_unlock(&obj->mm.lock);
- return 0;
+ if (unlikely(obj->mm.madv != I915_MADV_WILLNEED)) {
+ drm_dbg(obj->base.dev,
+ "Attempting to obtain a purgeable object\n");
+ err = -EFAULT;
+ goto out;
+ }
-err_xfer:
- obj->ops = &i915_gem_shmem_ops;
- if (!IS_ERR_OR_NULL(pages)) {
- unsigned int sg_page_sizes = i915_sg_page_sizes(pages->sgl);
+ err = i915_gem_object_shmem_to_phys(obj);
- __i915_gem_object_set_pages(obj, pages, sg_page_sizes);
- }
-err_unlock:
+out:
mutex_unlock(&obj->mm.lock);
return err;
}
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
index 1ad4713589da..e0778b3cc0c3 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
@@ -303,6 +303,11 @@ shmem_put_pages(struct drm_i915_gem_object *obj, struct sg_table *pages)
struct pagevec pvec;
struct page *page;
+ if (unlikely(!i915_gem_object_has_struct_page(obj))) {
+ i915_gem_object_put_pages_phys(obj, pages);
+ return;
+ }
+
__i915_gem_object_release_shmem(obj, pages, true);
i915_gem_gtt_finish_pages(obj, pages);
@@ -423,7 +428,8 @@ shmem_pwrite(struct drm_i915_gem_object *obj,
static void shmem_release(struct drm_i915_gem_object *obj)
{
- i915_gem_object_release_memory_region(obj);
+ if (obj->flags & I915_BO_ALLOC_STRUCT_PAGE)
+ i915_gem_object_release_memory_region(obj);
fput(obj->base.filp);
}
diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_phys.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_phys.c
index a94243dc4c5c..dc200ca8e041 100644
--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_phys.c
+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_phys.c
@@ -25,13 +25,19 @@ static int mock_phys_object(void *arg)
goto out;
}
+ if (!i915_gem_object_has_struct_page(obj)) {
+ pr_err("i915_gem_object_attach_phys did not set struct page backing\n");
+ err = -EINVAL;
+ goto out_obj;
+ }
+
err = i915_gem_object_attach_phys(obj, PAGE_SIZE);
if (err) {
pr_err("i915_gem_object_attach_phys failed, err=%d\n", err);
goto out_obj;
}
- if (obj->ops != &i915_gem_phys_ops) {
+ if (i915_gem_object_has_struct_page(obj)) {
pr_err("i915_gem_object_attach_phys did not create a phys object\n");
err = -EINVAL;
goto out_obj;
--
2.28.0
More information about the Intel-gfx-trybot
mailing list