summaryrefslogtreecommitdiffstats
path: root/drivers/staging/omapdrm/omap_gem_helpers.c
diff options
context:
space:
mode:
authorRob Clark2011-12-06 02:19:22 +0100
committerGreg Kroah-Hartman2011-12-09 00:04:21 +0100
commitf7f9f4536a09f9f73c800663df2e600c9405e1ef (patch)
tree690d369e969039a54fec3a813d60b7acf5ea8207 /drivers/staging/omapdrm/omap_gem_helpers.c
parentdrm/omap: DMM/TILER support for OMAP4+ platform (diff)
downloadkernel-qcow2-linux-f7f9f4536a09f9f73c800663df2e600c9405e1ef.tar.gz
kernel-qcow2-linux-f7f9f4536a09f9f73c800663df2e600c9405e1ef.tar.xz
kernel-qcow2-linux-f7f9f4536a09f9f73c800663df2e600c9405e1ef.zip
drm/omap: add GEM support for tiled/dmm buffers
TILER/DMM provides two features for omapdrm GEM objects: 1) providing a physically contiguous view to discontiguous memory for hw initiators that cannot otherwise support discontiguous buffers (DSS scanout, IVAHD video decode/encode, etc) 2) providing untiling for 2d tiled buffers, which are used in some cases to provide rotation and reduce memory bandwidth for hw initiators that tend to access data in 2d block patterns. For 2d tiled buffers, there are some additional complications when it comes to userspace mmap'ings. For non-tiled buffers, the original (potentially physically discontiguous) pages are used to back the mmap. For tiled buffers, we need to mmap via the tiler/dmm region to provide an unswizzled view of the buffer. But (a) the buffer is not necessarily pinned in TILER all the time (it can be unmapped when there is no DMA access to the buffer), and (b) when they are they are pinned, they not necessarily page aligned from the perspective of the CPU. And non-page aligned userspace buffer mapping is evil. To solve this, we reserve one or more small regions in each of the 2d containers when the driver is loaded to use as a "user-GART" where we can create a second page-aligned mapping of parts of the buffer being accessed from userspace. Page faulting is used to evict and remap different regions of whichever buffers are being accessed from user- space. Signed-off-by: Rob Clark <rob@ti.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/omapdrm/omap_gem_helpers.c')
-rw-r--r--drivers/staging/omapdrm/omap_gem_helpers.c55
1 files changed, 55 insertions, 0 deletions
diff --git a/drivers/staging/omapdrm/omap_gem_helpers.c b/drivers/staging/omapdrm/omap_gem_helpers.c
index 1cfc12d35593..29275c7209e9 100644
--- a/drivers/staging/omapdrm/omap_gem_helpers.c
+++ b/drivers/staging/omapdrm/omap_gem_helpers.c
@@ -112,3 +112,58 @@ void _drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages,
drm_free_large(pages);
}
+
+int
+_drm_gem_create_mmap_offset_size(struct drm_gem_object *obj, size_t size)
+{
+ struct drm_device *dev = obj->dev;
+ struct drm_gem_mm *mm = dev->mm_private;
+ struct drm_map_list *list;
+ struct drm_local_map *map;
+ int ret = 0;
+
+ /* Set the object up for mmap'ing */
+ list = &obj->map_list;
+ list->map = kzalloc(sizeof(struct drm_map_list), GFP_KERNEL);
+ if (!list->map)
+ return -ENOMEM;
+
+ map = list->map;
+ map->type = _DRM_GEM;
+ map->size = size;
+ map->handle = obj;
+
+ /* Get a DRM GEM mmap offset allocated... */
+ list->file_offset_node = drm_mm_search_free(&mm->offset_manager,
+ size / PAGE_SIZE, 0, 0);
+
+ if (!list->file_offset_node) {
+ DRM_ERROR("failed to allocate offset for bo %d\n", obj->name);
+ ret = -ENOSPC;
+ goto out_free_list;
+ }
+
+ list->file_offset_node = drm_mm_get_block(list->file_offset_node,
+ size / PAGE_SIZE, 0);
+ if (!list->file_offset_node) {
+ ret = -ENOMEM;
+ goto out_free_list;
+ }
+
+ list->hash.key = list->file_offset_node->start;
+ ret = drm_ht_insert_item(&mm->offset_hash, &list->hash);
+ if (ret) {
+ DRM_ERROR("failed to add to map hash\n");
+ goto out_free_mm;
+ }
+
+ return 0;
+
+out_free_mm:
+ drm_mm_put_block(list->file_offset_node);
+out_free_list:
+ kfree(list->map);
+ list->map = NULL;
+
+ return ret;
+}