aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/i915_drv.h
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2014-05-16 09:22:37 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2014-05-16 13:31:29 -0400
commit5cc9ed4b9a7ac579362ccebac67f7a4cdb36de06 (patch)
treee4d3acc17774d0bf64e46f42b566c190783c1972 /drivers/gpu/drm/i915/i915_drv.h
parent992f191f2c83f0d1184975a211070dff2a359d3b (diff)
drm/i915: Introduce mapping of user pages into video memory (userptr) ioctl
By exporting the ability to map user address and inserting PTEs representing their backing pages into the GTT, we can exploit UMA in order to utilize normal application data as a texture source or even as a render target (depending upon the capabilities of the chipset). This has a number of uses, with zero-copy downloads to the GPU and efficient readback making the intermixed streaming of CPU and GPU operations fairly efficient. This ability has many widespread implications from faster rendering of client-side software rasterisers (chromium), mitigation of stalls due to read back (firefox) and to faster pipelining of texture data (such as pixel buffer objects in GL or data blobs in CL). v2: Compile with CONFIG_MMU_NOTIFIER v3: We can sleep while performing invalidate-range, which we can utilise to drop our page references prior to the kernel manipulating the vma (for either discard or cloning) and so protect normal users. v4: Only run the invalidate notifier if the range intercepts the bo. v5: Prevent userspace from attempting to GTT mmap non-page aligned buffers v6: Recheck after reacquire mutex for lost mmu. v7: Fix implicit padding of ioctl struct by rounding to next 64bit boundary. v8: Fix rebasing error after forwarding porting the back port. v9: Limit the userptr to page aligned entries. We now expect userspace to handle all the offset-in-page adjustments itself. v10: Prevent vma from being copied across fork to avoid issues with cow. v11: Drop vma behaviour changes -- locking is nigh on impossible. Use a worker to load user pages to avoid lock inversions. v12: Use get_task_mm()/mmput() for correct refcounting of mm. v13: Use a worker to release the mmu_notifier to avoid lock inversion v14: Decouple mmu_notifier from struct_mutex using a custom mmu_notifer with its own locking and tree of objects for each mm/mmu_notifier. v15: Prevent overlapping userptr objects, and invalidate all objects within the mmu_notifier range v16: Fix a typo for iterating over multiple objects in the range and rearrange error path to destroy the mmu_notifier locklessly. Also close a race between invalidate_range and the get_pages_worker. v17: Close a race between get_pages_worker/invalidate_range and fresh allocations of the same userptr range - and notice that struct_mutex was presumed to be held when during creation it wasn't. v18: Sigh. Fix the refactor of st_set_pages() to allocate enough memory for the struct sg_table and to clear it before reporting an error. v19: Always error out on read-only userptr requests as we don't have the hardware infrastructure to support them at the moment. v20: Refuse to implement read-only support until we have the required infrastructure - but reserve the bit in flags for future use. v21: use_mm() is not required for get_user_pages(). It is only meant to be used to fix up the kernel thread's current->mm for use with copy_user(). v22: Use sg_alloc_table_from_pages for that chunky feeling v23: Export a function for sanity checking dma-buf rather than encode userptr details elsewhere, and clean up comments based on suggestions by Bradley. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com> Cc: "Gong, Zhipeng" <zhipeng.gong@intel.com> Cc: Akash Goel <akash.goel@intel.com> Cc: "Volkin, Bradley D" <bradley.d.volkin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com> Reviewed-by: Brad Volkin <bradley.d.volkin@intel.com> [danvet: Frob ioctl allocation to pick the next one - will cause a bit of fuss with create2 apparently, but such are the rules.] [danvet2: oops, forgot to git add after manual patch application] [danvet3: Appease sparse.] Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/i915_drv.h')
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h25
1 files changed, 24 insertions, 1 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 9e9e8166a1f3..a270e0773e2d 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -41,6 +41,7 @@
41#include <linux/i2c-algo-bit.h> 41#include <linux/i2c-algo-bit.h>
42#include <drm/intel-gtt.h> 42#include <drm/intel-gtt.h>
43#include <linux/backlight.h> 43#include <linux/backlight.h>
44#include <linux/hashtable.h>
44#include <linux/intel-iommu.h> 45#include <linux/intel-iommu.h>
45#include <linux/kref.h> 46#include <linux/kref.h>
46#include <linux/pm_qos.h> 47#include <linux/pm_qos.h>
@@ -178,6 +179,7 @@ enum hpd_pin {
178 if ((intel_connector)->base.encoder == (__encoder)) 179 if ((intel_connector)->base.encoder == (__encoder))
179 180
180struct drm_i915_private; 181struct drm_i915_private;
182struct i915_mmu_object;
181 183
182enum intel_dpll_id { 184enum intel_dpll_id {
183 DPLL_ID_PRIVATE = -1, /* non-shared dpll in use */ 185 DPLL_ID_PRIVATE = -1, /* non-shared dpll in use */
@@ -403,6 +405,7 @@ struct drm_i915_error_state {
403 u32 tiling:2; 405 u32 tiling:2;
404 u32 dirty:1; 406 u32 dirty:1;
405 u32 purgeable:1; 407 u32 purgeable:1;
408 u32 userptr:1;
406 s32 ring:4; 409 s32 ring:4;
407 u32 cache_level:3; 410 u32 cache_level:3;
408 } **active_bo, **pinned_bo; 411 } **active_bo, **pinned_bo;
@@ -1447,6 +1450,9 @@ struct drm_i915_private {
1447 struct i915_gtt gtt; /* VM representing the global address space */ 1450 struct i915_gtt gtt; /* VM representing the global address space */
1448 1451
1449 struct i915_gem_mm mm; 1452 struct i915_gem_mm mm;
1453#if defined(CONFIG_MMU_NOTIFIER)
1454 DECLARE_HASHTABLE(mmu_notifiers, 7);
1455#endif
1450 1456
1451 /* Kernel Modesetting */ 1457 /* Kernel Modesetting */
1452 1458
@@ -1580,6 +1586,8 @@ struct drm_i915_gem_object_ops {
1580 */ 1586 */
1581 int (*get_pages)(struct drm_i915_gem_object *); 1587 int (*get_pages)(struct drm_i915_gem_object *);
1582 void (*put_pages)(struct drm_i915_gem_object *); 1588 void (*put_pages)(struct drm_i915_gem_object *);
1589 int (*dmabuf_export)(struct drm_i915_gem_object *);
1590 void (*release)(struct drm_i915_gem_object *);
1583}; 1591};
1584 1592
1585struct drm_i915_gem_object { 1593struct drm_i915_gem_object {
@@ -1693,8 +1701,20 @@ struct drm_i915_gem_object {
1693 1701
1694 /** for phy allocated objects */ 1702 /** for phy allocated objects */
1695 struct drm_i915_gem_phys_object *phys_obj; 1703 struct drm_i915_gem_phys_object *phys_obj;
1696};
1697 1704
1705 union {
1706 struct i915_gem_userptr {
1707 uintptr_t ptr;
1708 unsigned read_only :1;
1709 unsigned workers :4;
1710#define I915_GEM_USERPTR_MAX_WORKERS 15
1711
1712 struct mm_struct *mm;
1713 struct i915_mmu_object *mn;
1714 struct work_struct *work;
1715 } userptr;
1716 };
1717};
1698#define to_intel_bo(x) container_of(x, struct drm_i915_gem_object, base) 1718#define to_intel_bo(x) container_of(x, struct drm_i915_gem_object, base)
1699 1719
1700/** 1720/**
@@ -2119,6 +2139,9 @@ int i915_gem_set_tiling(struct drm_device *dev, void *data,
2119 struct drm_file *file_priv); 2139 struct drm_file *file_priv);
2120int i915_gem_get_tiling(struct drm_device *dev, void *data, 2140int i915_gem_get_tiling(struct drm_device *dev, void *data,
2121 struct drm_file *file_priv); 2141 struct drm_file *file_priv);
2142int i915_gem_init_userptr(struct drm_device *dev);
2143int i915_gem_userptr_ioctl(struct drm_device *dev, void *data,
2144 struct drm_file *file);
2122int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, 2145int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
2123 struct drm_file *file_priv); 2146 struct drm_file *file_priv);
2124int i915_gem_wait_ioctl(struct drm_device *dev, void *data, 2147int i915_gem_wait_ioctl(struct drm_device *dev, void *data,