diff options
author | Linus Torvalds | 2012-01-09 21:18:17 +0100 |
---|---|---|
committer | Linus Torvalds | 2012-01-09 21:18:17 +0100 |
commit | 12e55508921865aefdd80fd17afe70c191afbd1b (patch) | |
tree | 476b3226fd9602b36bed0934409959bdd24a7eb5 /drivers/staging/omapdrm/omap_gem_helpers.c | |
parent | Merge branch 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/greg... (diff) | |
parent | net/hyperv: Add support for jumbo frame up to 64KB (diff) | |
download | kernel-qcow2-linux-12e55508921865aefdd80fd17afe70c191afbd1b.tar.gz kernel-qcow2-linux-12e55508921865aefdd80fd17afe70c191afbd1b.tar.xz kernel-qcow2-linux-12e55508921865aefdd80fd17afe70c191afbd1b.zip |
Merge branch 'staging-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging
* 'staging-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (466 commits)
net/hyperv: Add support for jumbo frame up to 64KB
net/hyperv: Add NETVSP protocol version negotiation
net/hyperv: Remove unnecessary kmap_atomic in netvsc driver
staging/rtl8192e: Register against lib80211
staging/rtl8192e: Convert to lib80211_crypt_info
staging/rtl8192e: Convert to lib80211_crypt_data and lib80211_crypt_ops
staging/rtl8192e: Add lib80211.h to rtllib.h
staging/mei: add watchdog device registration wrappers
drm/omap: GEM, deal with cache
staging: vt6656: int.c, int.h: Change return of function to void
staging: usbip: removed unused definitions from header
staging: usbip: removed dead code from receive function
staging:iio: Drop {mark,unmark}_in_use callbacks
staging:iio: Drop buffer mark_param_change callback
staging:iio: Drop the unused buffer enable() and is_enabled() callbacks
staging:iio: Drop buffer busy flag
staging:iio: Make sure a device is only opened once at a time
staging:iio: Disallow modifying buffer size when buffer is enabled
staging:iio: Disallow changing scan elements in all buffered modes
staging:iio: Use iio_buffer_enabled instead of open coding it
...
Fix up conflict in drivers/staging/iio/adc/ad799x_core.c (removal of
module_init due to using module_i2c_driver() helper, next to removal of
MODULE_ALIAS due to using MODULE_DEVICE_TABLE instead).
Diffstat (limited to 'drivers/staging/omapdrm/omap_gem_helpers.c')
-rw-r--r-- | drivers/staging/omapdrm/omap_gem_helpers.c | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/drivers/staging/omapdrm/omap_gem_helpers.c b/drivers/staging/omapdrm/omap_gem_helpers.c new file mode 100644 index 000000000000..29275c7209e9 --- /dev/null +++ b/drivers/staging/omapdrm/omap_gem_helpers.c @@ -0,0 +1,169 @@ +/* + * drivers/staging/omapdrm/omap_gem_helpers.c + * + * Copyright (C) 2011 Texas Instruments + * Author: Rob Clark <rob.clark@linaro.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/* temporary copy of drm_gem_{get,put}_pages() until the + * "drm/gem: add functions to get/put pages" patch is merged.. + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/shmem_fs.h> + +#include <drm/drmP.h> + +/** + * drm_gem_get_pages - helper to allocate backing pages for a GEM object + * @obj: obj in question + * @gfpmask: gfp mask of requested pages + */ +struct page ** _drm_gem_get_pages(struct drm_gem_object *obj, gfp_t gfpmask) +{ + struct inode *inode; + struct address_space *mapping; + struct page *p, **pages; + int i, npages; + + /* This is the shared memory object that backs the GEM resource */ + inode = obj->filp->f_path.dentry->d_inode; + mapping = inode->i_mapping; + + npages = obj->size >> PAGE_SHIFT; + + pages = drm_malloc_ab(npages, sizeof(struct page *)); + if (pages == NULL) + return ERR_PTR(-ENOMEM); + + gfpmask |= mapping_gfp_mask(mapping); + + for (i = 0; i < npages; i++) { + p = shmem_read_mapping_page_gfp(mapping, i, gfpmask); + if (IS_ERR(p)) + goto fail; + pages[i] = p; + + /* There is a hypothetical issue w/ drivers that require + * buffer memory in the low 4GB.. if the pages are un- + * pinned, and swapped out, they can end up swapped back + * in above 4GB. If pages are already in memory, then + * shmem_read_mapping_page_gfp will ignore the gfpmask, + * even if the already in-memory page disobeys the mask. + * + * It is only a theoretical issue today, because none of + * the devices with this limitation can be populated with + * enough memory to trigger the issue. But this BUG_ON() + * is here as a reminder in case the problem with + * shmem_read_mapping_page_gfp() isn't solved by the time + * it does become a real issue. + * + * See this thread: http://lkml.org/lkml/2011/7/11/238 + */ + BUG_ON((gfpmask & __GFP_DMA32) && + (page_to_pfn(p) >= 0x00100000UL)); + } + + return pages; + +fail: + while (i--) { + page_cache_release(pages[i]); + } + drm_free_large(pages); + return ERR_PTR(PTR_ERR(p)); +} + +/** + * drm_gem_put_pages - helper to free backing pages for a GEM object + * @obj: obj in question + * @pages: pages to free + */ +void _drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, + bool dirty, bool accessed) +{ + int i, npages; + + npages = obj->size >> PAGE_SHIFT; + + for (i = 0; i < npages; i++) { + if (dirty) + set_page_dirty(pages[i]); + + if (accessed) + mark_page_accessed(pages[i]); + + /* Undo the reference we took when populating the table */ + page_cache_release(pages[i]); + } + + 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; +} |