VIGS: Make GEM access tracking optional
authorStanislav Vorobiov <s.vorobiov@samsung.com>
Thu, 11 Jul 2013 06:43:20 +0000 (10:43 +0400)
committerStanislav Vorobiov <s.vorobiov@samsung.com>
Thu, 11 Jul 2013 06:43:20 +0000 (10:43 +0400)
For dumb GEM API we need to have GEM access tracking
disabled and always assume that access is RW.
Thus, we make GEM access tracking optional, so that user-mode
can specify if it's wanted or not

drivers/gpu/drm/vigs/vigs_device.c
drivers/gpu/drm/vigs/vigs_device.h
drivers/gpu/drm/vigs/vigs_driver.c
drivers/gpu/drm/vigs/vigs_execbuffer.c
drivers/gpu/drm/vigs/vigs_gem.c
drivers/gpu/drm/vigs/vigs_gem.h
drivers/gpu/drm/vigs/vigs_mman.c
drivers/gpu/drm/vigs/vigs_mman.h
drivers/gpu/drm/vigs/vigs_surface.c
drivers/gpu/drm/vigs/vigs_surface.h
include/drm/vigs_drm.h

index 7e21c4a88b669c91f6113326c00344c7204ed722..a39152b0e5f54e61022992b44b3dab0d021667ab 100644 (file)
@@ -51,7 +51,8 @@ static void vigs_device_mman_gpu_to_vram(void *user_data,
 
 static void vigs_device_mman_init_vma(void *user_data,
                                       void *vma_data_opaque,
-                                      struct ttm_buffer_object *bo)
+                                      struct ttm_buffer_object *bo,
+                                      bool track_access)
 {
     struct vigs_vma_data *vma_data = vma_data_opaque;
     struct vigs_gem_object *vigs_gem = bo_to_vigs_gem(bo);
@@ -61,7 +62,9 @@ static void vigs_device_mman_init_vma(void *user_data,
         return;
     }
 
-    vigs_vma_data_init(vma_data, vigs_gem_to_vigs_surface(vigs_gem));
+    vigs_vma_data_init(vma_data,
+                       vigs_gem_to_vigs_surface(vigs_gem),
+                       track_access);
 }
 
 static void vigs_device_mman_cleanup_vma(void *user_data,
@@ -429,7 +432,10 @@ int vigs_device_mmap(struct file *filp, struct vm_area_struct *vma)
         return -EINVAL;
     }
 
-    return vigs_mman_mmap(vigs_dev->mman, filp, vma);
+    return vigs_mman_mmap(vigs_dev->mman,
+                          filp,
+                          vma,
+                          vigs_dev->track_gem_access);
 }
 
 int vigs_device_add_surface(struct vigs_device *vigs_dev,
index 29f09c10431a0a618463dcbf90a55a18d0906452..88e8dde4a7a9edb7c0e315f9ba9459fc3f67412a 100644 (file)
@@ -36,6 +36,14 @@ struct vigs_device
     struct vigs_comm *comm;
 
     struct vigs_fbdev *fbdev;
+
+    /*
+     * A hack we're forced to have in order to tell if we
+     * need to track GEM access or not in 'vigs_device_mmap'.
+     * current's 'mmap_sem' is write-locked while this is true,
+     * so no race will occur.
+     */
+    bool track_gem_access;
 };
 
 int vigs_device_init(struct vigs_device *vigs_dev,
index 635157736d20bf006063690dba1af698bc1187d6..73da60637c10c6c5c4f2b1f043c04b3bde9530ac 100644 (file)
@@ -40,6 +40,8 @@ static struct drm_ioctl_desc vigs_drm_ioctls[] =
                                            DRM_UNLOCKED | DRM_AUTH),
     DRM_IOCTL_DEF_DRV(VIGS_CREATE_EXECBUFFER, vigs_execbuffer_create_ioctl,
                                               DRM_UNLOCKED | DRM_AUTH),
+    DRM_IOCTL_DEF_DRV(VIGS_GEM_MAP, vigs_gem_map_ioctl,
+                                    DRM_UNLOCKED | DRM_AUTH),
     DRM_IOCTL_DEF_DRV(VIGS_SURFACE_INFO, vigs_surface_info_ioctl,
                                          DRM_UNLOCKED | DRM_AUTH),
     DRM_IOCTL_DEF_DRV(VIGS_EXEC, vigs_device_exec_ioctl,
index 580a57c9c4afc0387acb3a187203c2b72bd0ab1f..6a65a800ad610d7314f1d947b83602f529fb1f8a 100644 (file)
@@ -69,7 +69,6 @@ int vigs_execbuffer_create_ioctl(struct drm_device *drm_dev,
     if (ret == 0) {
         args->size = vigs_gem_size(&execbuffer->gem);
         args->handle = handle;
-        args->mmap_offset = vigs_gem_mmap_offset(&execbuffer->gem);
     }
 
     return ret;
index cc5761c5820d8f73ce2f06a241150c56ec794a22..39b383756ef311fe09a11d3b802f5418b01113df 100644 (file)
@@ -277,6 +277,57 @@ void vigs_gem_close_object(struct drm_gem_object *gem,
 {
 }
 
+int vigs_gem_map_ioctl(struct drm_device *drm_dev,
+                       void *data,
+                       struct drm_file *file_priv)
+{
+    struct vigs_device *vigs_dev = drm_dev->dev_private;
+    struct drm_vigs_gem_map *args = data;
+    struct drm_gem_object *gem;
+    struct vigs_gem_object *vigs_gem;
+    struct mm_struct *mm = current->mm;
+    unsigned long address;
+
+    gem = drm_gem_object_lookup(drm_dev, file_priv, args->handle);
+
+    if (gem == NULL) {
+        return -ENOENT;
+    }
+
+    vigs_gem = gem_to_vigs_gem(gem);
+
+    down_write(&mm->mmap_sem);
+
+    /*
+     * We can't use 'do_mmap' here (like in i915, exynos and others) because
+     * 'do_mmap' takes an offset in bytes and our
+     * offset is 64-bit (since it's TTM offset) and it can't fit into 32-bit
+     * variable.
+     * For this to work we had to export
+     * 'do_mmap_pgoff'. 'do_mmap_pgoff' was exported prior to
+     * 3.4 and it's available after 3.5, but for some reason it's
+     * static in 3.4.
+     */
+    vigs_dev->track_gem_access = args->track_access;
+    address = do_mmap_pgoff(file_priv->filp, 0, vigs_gem_size(vigs_gem),
+                            PROT_READ | PROT_WRITE,
+                            MAP_SHARED,
+                            vigs_gem_mmap_offset(vigs_gem) >> PAGE_SHIFT);
+    vigs_dev->track_gem_access = false;
+
+    up_write(&mm->mmap_sem);
+
+    drm_gem_object_unreference_unlocked(gem);
+
+    if (IS_ERR((void*)address)) {
+        return PTR_ERR((void*)address);
+    }
+
+    args->address = address;
+
+    return 0;
+}
+
 int vigs_gem_dumb_create(struct drm_file *file_priv,
                          struct drm_device *drm_dev,
                          struct drm_mode_create_dumb *args)
index 25280d5c3f17c648d2b88d9c29b82fba1eb53046..51405c46831c2230233d8e0264e3bce4ebe350ab 100644 (file)
@@ -164,6 +164,19 @@ void vigs_gem_close_object(struct drm_gem_object *gem,
  * @}
  */
 
+/*
+ * IOCTLs
+ * @{
+ */
+
+int vigs_gem_map_ioctl(struct drm_device *drm_dev,
+                       void *data,
+                       struct drm_file *file_priv);
+
+/*
+ * @}
+ */
+
 /*
  * Dumb
  * @{
index 68452bac368d4576df2f53bfcc2bf85659f2c969..341f5097cfd267f4796a8237a8a586f2a8818d91 100644 (file)
@@ -586,7 +586,8 @@ static int vigs_ttm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 
 int vigs_mman_mmap(struct vigs_mman *mman,
                    struct file *filp,
-                   struct vm_area_struct *vma)
+                   struct vm_area_struct *vma,
+                   bool track_access)
 {
     struct vigs_mman_vma *vigs_vma;
     int ret;
@@ -622,7 +623,10 @@ int vigs_mman_mmap(struct vigs_mman *mman,
     vigs_vma->vm_ops.open = &vigs_ttm_open;
     vigs_vma->vm_ops.close = &vigs_ttm_close;
     kref_init(&vigs_vma->kref);
-    mman->ops->init_vma(mman->user_data, &vigs_vma->data[0], bo);
+    mman->ops->init_vma(mman->user_data,
+                        &vigs_vma->data[0],
+                        bo,
+                        track_access);
 
     vma->vm_ops = &vigs_vma->vm_ops;
 
index a04c2196f6d6ce1da54c77c5fa589e6dd939b9fd..286e99ae1b31c067cdfa551822cf8af3074eeadb 100644 (file)
@@ -23,12 +23,15 @@ struct vigs_mman_ops
      * Per-VMA data init/cleanup. VMA may be opened/closed many times
      * as the result of split/copy, but the init/cleanup handlers are called
      * only once, i.e. vigs_mman is handling the reference counts.
+     *
+     * current's 'mmap_sem' is locked while calling this.
      * @{
      */
 
     void (*init_vma)(void *user_data,
                      void *vma_data,
-                     struct ttm_buffer_object *bo);
+                     struct ttm_buffer_object *bo,
+                     bool track_access);
 
     /*
      * current's 'mmap_sem' is locked while calling this.
@@ -75,7 +78,8 @@ void vigs_mman_destroy(struct vigs_mman *mman);
 
 int vigs_mman_mmap(struct vigs_mman *mman,
                    struct file *filp,
-                   struct vm_area_struct *vma);
+                   struct vm_area_struct *vma,
+                   bool track_access);
 
 /*
  * current's 'mmap_sem' is locked while calling 'func'.
index ba2e2799ef978cdb0faf9b29aafdd3c1649c0976..c1b1bf0141a8476c90fba5b0a067acc8f01dec01 100644 (file)
@@ -98,17 +98,57 @@ out:
  */
 
 void vigs_vma_data_init(struct vigs_vma_data *vma_data,
-                        struct vigs_surface *sfc)
+                        struct vigs_surface *sfc,
+                        bool track_access)
 {
+    struct vigs_device *vigs_dev = sfc->gem.base.dev->dev_private;
+    u32 old_saf;
+
     vma_data->sfc = sfc;
     vma_data->saf = 0;
+    vma_data->track_access = track_access;
+
+    if (track_access) {
+        return;
+    }
+
+    /*
+     * If we don't want to track access for this VMA
+     * then register as both reader and writer.
+     */
+
+    vigs_gem_reserve(&sfc->gem);
+
+    old_saf = vigs_surface_saf(sfc);
+
+    ++sfc->num_writers;
+    ++sfc->num_readers;
+
+    if (vigs_gem_in_vram(&sfc->gem) && sfc->is_gpu_dirty) {
+        vigs_comm_update_vram(vigs_dev->comm,
+                              sfc->id,
+                              vigs_gem_offset(&sfc->gem));
+        sfc->is_gpu_dirty = false;
+    }
+
+    vma_data->saf = DRM_VIGS_SAF_READ | DRM_VIGS_SAF_WRITE;
+
+    vigs_surface_saf_changed(sfc, old_saf);
+
+    vigs_gem_unreserve(&sfc->gem);
 }
 
 void vigs_vma_data_cleanup(struct vigs_vma_data *vma_data)
 {
     vigs_gem_reserve(&vma_data->sfc->gem);
 
-    vigs_vma_data_end_access(vma_data, true);
+    /*
+     * On unmap we sync only when access tracking is enabled.
+     * Otherwise, we pretend we're going to sync
+     * some time later, but we never will.
+     */
+    vigs_vma_data_end_access(vma_data,
+                             vma_data->track_access);
 
     vigs_gem_unreserve(&vma_data->sfc->gem);
 }
@@ -238,7 +278,6 @@ int vigs_surface_create_ioctl(struct drm_device *drm_dev,
     if (ret == 0) {
         args->handle = handle;
         args->size = vigs_gem_size(&sfc->gem);
-        args->mmap_offset = vigs_gem_mmap_offset(&sfc->gem);
         args->id = sfc->id;
     }
 
@@ -274,7 +313,6 @@ int vigs_surface_info_ioctl(struct drm_device *drm_dev,
     args->stride = sfc->stride;
     args->format = sfc->format;
     args->size = vigs_gem_size(vigs_gem);
-    args->mmap_offset = vigs_gem_mmap_offset(vigs_gem);
     args->id = sfc->id;
 
     drm_gem_object_unreference_unlocked(gem);
@@ -331,6 +369,10 @@ static int vigs_surface_start_access(void *user_data, void *vma_data_opaque)
         return -ENOENT;
     }
 
+    if (!vma_data->track_access) {
+        return 0;
+    }
+
     vigs_dev = sfc->gem.base.dev->dev_private;
 
     if ((args->saf & ~DRM_VIGS_SAF_MASK) != 0) {
@@ -396,6 +438,10 @@ static int vigs_surface_end_access(void *user_data, void *vma_data_opaque)
         return -ENOENT;
     }
 
+    if (!vma_data->track_access) {
+        return 0;
+    }
+
     vigs_gem_reserve(&sfc->gem);
 
     vigs_vma_data_end_access(vma_data, args->sync);
index 01762dfcdc9f41cbfe35cca9845b129e62c1a20f..1fe99b7223eabfa0dff127416c469da3dd1c4737 100644 (file)
@@ -59,10 +59,12 @@ struct vigs_vma_data
 {
     struct vigs_surface *sfc;
     u32 saf;
+    bool track_access;
 };
 
 void vigs_vma_data_init(struct vigs_vma_data *vma_data,
-                        struct vigs_surface *sfc);
+                        struct vigs_surface *sfc,
+                        bool track_access);
 
 void vigs_vma_data_cleanup(struct vigs_vma_data *vma_data);
 
index 156968473b337decf7eaae2df701e358127c59c6..179ea914606d7dcb284faa45bce8435d16844a1a 100644 (file)
@@ -8,7 +8,7 @@
 /*
  * Bump this whenever driver interface changes.
  */
-#define DRM_VIGS_DRIVER_VERSION 8
+#define DRM_VIGS_DRIVER_VERSION 9
 
 /*
  * Surface access flags.
@@ -30,7 +30,6 @@ struct drm_vigs_create_surface
     uint32_t format;
     uint32_t handle;
     uint32_t size;
-    uint64_t mmap_offset;
     uint32_t id;
 };
 
@@ -38,7 +37,13 @@ struct drm_vigs_create_execbuffer
 {
     uint32_t size;
     uint32_t handle;
-    uint64_t mmap_offset;
+};
+
+struct drm_vigs_gem_map
+{
+    uint32_t handle;
+    int track_access;
+    unsigned long address;
 };
 
 struct drm_vigs_surface_info
@@ -49,7 +54,6 @@ struct drm_vigs_surface_info
     uint32_t stride;
     uint32_t format;
     uint32_t size;
-    uint64_t mmap_offset;
     uint32_t id;
 };
 
@@ -78,11 +82,12 @@ struct drm_vigs_surface_end_access
 #define DRM_VIGS_GET_PROTOCOL_VERSION 0x00
 #define DRM_VIGS_CREATE_SURFACE 0x01
 #define DRM_VIGS_CREATE_EXECBUFFER 0x02
-#define DRM_VIGS_SURFACE_INFO 0x03
-#define DRM_VIGS_EXEC 0x04
-#define DRM_VIGS_SURFACE_SET_GPU_DIRTY 0x05
-#define DRM_VIGS_SURFACE_START_ACCESS 0x06
-#define DRM_VIGS_SURFACE_END_ACCESS 0x07
+#define DRM_VIGS_GEM_MAP 0x03
+#define DRM_VIGS_SURFACE_INFO 0x04
+#define DRM_VIGS_EXEC 0x05
+#define DRM_VIGS_SURFACE_SET_GPU_DIRTY 0x06
+#define DRM_VIGS_SURFACE_START_ACCESS 0x07
+#define DRM_VIGS_SURFACE_END_ACCESS 0x08
 
 #define DRM_IOCTL_VIGS_GET_PROTOCOL_VERSION DRM_IOR(DRM_COMMAND_BASE + \
             DRM_VIGS_GET_PROTOCOL_VERSION, struct drm_vigs_get_protocol_version)
@@ -90,6 +95,8 @@ struct drm_vigs_surface_end_access
             DRM_VIGS_CREATE_SURFACE, struct drm_vigs_create_surface)
 #define DRM_IOCTL_VIGS_CREATE_EXECBUFFER DRM_IOWR(DRM_COMMAND_BASE + \
             DRM_VIGS_CREATE_EXECBUFFER, struct drm_vigs_create_execbuffer)
+#define DRM_IOCTL_VIGS_GEM_MAP DRM_IOWR(DRM_COMMAND_BASE + \
+            DRM_VIGS_GEM_MAP, struct drm_vigs_gem_map)
 #define DRM_IOCTL_VIGS_SURFACE_INFO DRM_IOWR(DRM_COMMAND_BASE + \
             DRM_VIGS_SURFACE_INFO, struct drm_vigs_surface_info)
 #define DRM_IOCTL_VIGS_EXEC DRM_IOW(DRM_COMMAND_BASE + \