Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.7-rc2 251 lines 6.3 kB view raw
1/* 2 * drm gem CMA (contiguous memory allocator) helper functions 3 * 4 * Copyright (C) 2012 Sascha Hauer, Pengutronix 5 * 6 * Based on Samsung Exynos code 7 * 8 * Copyright (c) 2011 Samsung Electronics Co., Ltd. 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License 12 * as published by the Free Software Foundation; either version 2 13 * of the License, or (at your option) any later version. 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 */ 19 20#include <linux/mm.h> 21#include <linux/slab.h> 22#include <linux/mutex.h> 23#include <linux/export.h> 24#include <linux/dma-mapping.h> 25 26#include <drm/drmP.h> 27#include <drm/drm.h> 28#include <drm/drm_gem_cma_helper.h> 29 30static unsigned int get_gem_mmap_offset(struct drm_gem_object *obj) 31{ 32 return (unsigned int)obj->map_list.hash.key << PAGE_SHIFT; 33} 34 35static void drm_gem_cma_buf_destroy(struct drm_device *drm, 36 struct drm_gem_cma_object *cma_obj) 37{ 38 dma_free_writecombine(drm->dev, cma_obj->base.size, cma_obj->vaddr, 39 cma_obj->paddr); 40} 41 42/* 43 * drm_gem_cma_create - allocate an object with the given size 44 * 45 * returns a struct drm_gem_cma_object* on success or ERR_PTR values 46 * on failure. 47 */ 48struct drm_gem_cma_object *drm_gem_cma_create(struct drm_device *drm, 49 unsigned int size) 50{ 51 struct drm_gem_cma_object *cma_obj; 52 struct drm_gem_object *gem_obj; 53 int ret; 54 55 size = round_up(size, PAGE_SIZE); 56 57 cma_obj = kzalloc(sizeof(*cma_obj), GFP_KERNEL); 58 if (!cma_obj) 59 return ERR_PTR(-ENOMEM); 60 61 cma_obj->vaddr = dma_alloc_writecombine(drm->dev, size, 62 &cma_obj->paddr, GFP_KERNEL | __GFP_NOWARN); 63 if (!cma_obj->vaddr) { 64 dev_err(drm->dev, "failed to allocate buffer with size %d\n", size); 65 ret = -ENOMEM; 66 goto err_dma_alloc; 67 } 68 69 gem_obj = &cma_obj->base; 70 71 ret = drm_gem_object_init(drm, gem_obj, size); 72 if (ret) 73 goto err_obj_init; 74 75 ret = drm_gem_create_mmap_offset(gem_obj); 76 if (ret) 77 goto err_create_mmap_offset; 78 79 return cma_obj; 80 81err_create_mmap_offset: 82 drm_gem_object_release(gem_obj); 83 84err_obj_init: 85 drm_gem_cma_buf_destroy(drm, cma_obj); 86 87err_dma_alloc: 88 kfree(cma_obj); 89 90 return ERR_PTR(ret); 91} 92EXPORT_SYMBOL_GPL(drm_gem_cma_create); 93 94/* 95 * drm_gem_cma_create_with_handle - allocate an object with the given 96 * size and create a gem handle on it 97 * 98 * returns a struct drm_gem_cma_object* on success or ERR_PTR values 99 * on failure. 100 */ 101static struct drm_gem_cma_object *drm_gem_cma_create_with_handle( 102 struct drm_file *file_priv, 103 struct drm_device *drm, unsigned int size, 104 unsigned int *handle) 105{ 106 struct drm_gem_cma_object *cma_obj; 107 struct drm_gem_object *gem_obj; 108 int ret; 109 110 cma_obj = drm_gem_cma_create(drm, size); 111 if (IS_ERR(cma_obj)) 112 return cma_obj; 113 114 gem_obj = &cma_obj->base; 115 116 /* 117 * allocate a id of idr table where the obj is registered 118 * and handle has the id what user can see. 119 */ 120 ret = drm_gem_handle_create(file_priv, gem_obj, handle); 121 if (ret) 122 goto err_handle_create; 123 124 /* drop reference from allocate - handle holds it now. */ 125 drm_gem_object_unreference_unlocked(gem_obj); 126 127 return cma_obj; 128 129err_handle_create: 130 drm_gem_cma_free_object(gem_obj); 131 132 return ERR_PTR(ret); 133} 134 135/* 136 * drm_gem_cma_free_object - (struct drm_driver)->gem_free_object callback 137 * function 138 */ 139void drm_gem_cma_free_object(struct drm_gem_object *gem_obj) 140{ 141 struct drm_gem_cma_object *cma_obj; 142 143 if (gem_obj->map_list.map) 144 drm_gem_free_mmap_offset(gem_obj); 145 146 drm_gem_object_release(gem_obj); 147 148 cma_obj = to_drm_gem_cma_obj(gem_obj); 149 150 drm_gem_cma_buf_destroy(gem_obj->dev, cma_obj); 151 152 kfree(cma_obj); 153} 154EXPORT_SYMBOL_GPL(drm_gem_cma_free_object); 155 156/* 157 * drm_gem_cma_dumb_create - (struct drm_driver)->dumb_create callback 158 * function 159 * 160 * This aligns the pitch and size arguments to the minimum required. wrap 161 * this into your own function if you need bigger alignment. 162 */ 163int drm_gem_cma_dumb_create(struct drm_file *file_priv, 164 struct drm_device *dev, struct drm_mode_create_dumb *args) 165{ 166 struct drm_gem_cma_object *cma_obj; 167 int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8); 168 169 if (args->pitch < min_pitch) 170 args->pitch = min_pitch; 171 172 if (args->size < args->pitch * args->height) 173 args->size = args->pitch * args->height; 174 175 cma_obj = drm_gem_cma_create_with_handle(file_priv, dev, 176 args->size, &args->handle); 177 if (IS_ERR(cma_obj)) 178 return PTR_ERR(cma_obj); 179 180 return 0; 181} 182EXPORT_SYMBOL_GPL(drm_gem_cma_dumb_create); 183 184/* 185 * drm_gem_cma_dumb_map_offset - (struct drm_driver)->dumb_map_offset callback 186 * function 187 */ 188int drm_gem_cma_dumb_map_offset(struct drm_file *file_priv, 189 struct drm_device *drm, uint32_t handle, uint64_t *offset) 190{ 191 struct drm_gem_object *gem_obj; 192 193 mutex_lock(&drm->struct_mutex); 194 195 gem_obj = drm_gem_object_lookup(drm, file_priv, handle); 196 if (!gem_obj) { 197 dev_err(drm->dev, "failed to lookup gem object\n"); 198 mutex_unlock(&drm->struct_mutex); 199 return -EINVAL; 200 } 201 202 *offset = get_gem_mmap_offset(gem_obj); 203 204 drm_gem_object_unreference(gem_obj); 205 206 mutex_unlock(&drm->struct_mutex); 207 208 return 0; 209} 210EXPORT_SYMBOL_GPL(drm_gem_cma_dumb_map_offset); 211 212const struct vm_operations_struct drm_gem_cma_vm_ops = { 213 .open = drm_gem_vm_open, 214 .close = drm_gem_vm_close, 215}; 216EXPORT_SYMBOL_GPL(drm_gem_cma_vm_ops); 217 218/* 219 * drm_gem_cma_mmap - (struct file_operation)->mmap callback function 220 */ 221int drm_gem_cma_mmap(struct file *filp, struct vm_area_struct *vma) 222{ 223 struct drm_gem_object *gem_obj; 224 struct drm_gem_cma_object *cma_obj; 225 int ret; 226 227 ret = drm_gem_mmap(filp, vma); 228 if (ret) 229 return ret; 230 231 gem_obj = vma->vm_private_data; 232 cma_obj = to_drm_gem_cma_obj(gem_obj); 233 234 ret = remap_pfn_range(vma, vma->vm_start, cma_obj->paddr >> PAGE_SHIFT, 235 vma->vm_end - vma->vm_start, vma->vm_page_prot); 236 if (ret) 237 drm_gem_vm_close(vma); 238 239 return ret; 240} 241EXPORT_SYMBOL_GPL(drm_gem_cma_mmap); 242 243/* 244 * drm_gem_cma_dumb_destroy - (struct drm_driver)->dumb_destroy callback function 245 */ 246int drm_gem_cma_dumb_destroy(struct drm_file *file_priv, 247 struct drm_device *drm, unsigned int handle) 248{ 249 return drm_gem_handle_delete(file_priv, handle); 250} 251EXPORT_SYMBOL_GPL(drm_gem_cma_dumb_destroy);