Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v3.10 270 lines 6.0 kB view raw
1/* 2 * NVIDIA Tegra DRM GEM helper functions 3 * 4 * Copyright (C) 2012 Sascha Hauer, Pengutronix 5 * Copyright (C) 2013 NVIDIA CORPORATION, All rights reserved. 6 * 7 * Based on the GEM/CMA helpers 8 * 9 * Copyright (c) 2011 Samsung Electronics Co., Ltd. 10 * 11 * This program is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU General Public License 13 * as published by the Free Software Foundation; either version 2 14 * of the License, or (at your option) any later version. 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 */ 20 21#include <linux/mm.h> 22#include <linux/slab.h> 23#include <linux/mutex.h> 24#include <linux/export.h> 25#include <linux/dma-mapping.h> 26 27#include <drm/drmP.h> 28#include <drm/drm.h> 29 30#include "gem.h" 31 32static inline struct tegra_bo *host1x_to_drm_bo(struct host1x_bo *bo) 33{ 34 return container_of(bo, struct tegra_bo, base); 35} 36 37static void tegra_bo_put(struct host1x_bo *bo) 38{ 39 struct tegra_bo *obj = host1x_to_drm_bo(bo); 40 struct drm_device *drm = obj->gem.dev; 41 42 mutex_lock(&drm->struct_mutex); 43 drm_gem_object_unreference(&obj->gem); 44 mutex_unlock(&drm->struct_mutex); 45} 46 47static dma_addr_t tegra_bo_pin(struct host1x_bo *bo, struct sg_table **sgt) 48{ 49 struct tegra_bo *obj = host1x_to_drm_bo(bo); 50 51 return obj->paddr; 52} 53 54static void tegra_bo_unpin(struct host1x_bo *bo, struct sg_table *sgt) 55{ 56} 57 58static void *tegra_bo_mmap(struct host1x_bo *bo) 59{ 60 struct tegra_bo *obj = host1x_to_drm_bo(bo); 61 62 return obj->vaddr; 63} 64 65static void tegra_bo_munmap(struct host1x_bo *bo, void *addr) 66{ 67} 68 69static void *tegra_bo_kmap(struct host1x_bo *bo, unsigned int page) 70{ 71 struct tegra_bo *obj = host1x_to_drm_bo(bo); 72 73 return obj->vaddr + page * PAGE_SIZE; 74} 75 76static void tegra_bo_kunmap(struct host1x_bo *bo, unsigned int page, 77 void *addr) 78{ 79} 80 81static struct host1x_bo *tegra_bo_get(struct host1x_bo *bo) 82{ 83 struct tegra_bo *obj = host1x_to_drm_bo(bo); 84 struct drm_device *drm = obj->gem.dev; 85 86 mutex_lock(&drm->struct_mutex); 87 drm_gem_object_reference(&obj->gem); 88 mutex_unlock(&drm->struct_mutex); 89 90 return bo; 91} 92 93const struct host1x_bo_ops tegra_bo_ops = { 94 .get = tegra_bo_get, 95 .put = tegra_bo_put, 96 .pin = tegra_bo_pin, 97 .unpin = tegra_bo_unpin, 98 .mmap = tegra_bo_mmap, 99 .munmap = tegra_bo_munmap, 100 .kmap = tegra_bo_kmap, 101 .kunmap = tegra_bo_kunmap, 102}; 103 104static void tegra_bo_destroy(struct drm_device *drm, struct tegra_bo *bo) 105{ 106 dma_free_writecombine(drm->dev, bo->gem.size, bo->vaddr, bo->paddr); 107} 108 109unsigned int tegra_bo_get_mmap_offset(struct tegra_bo *bo) 110{ 111 return (unsigned int)bo->gem.map_list.hash.key << PAGE_SHIFT; 112} 113 114struct tegra_bo *tegra_bo_create(struct drm_device *drm, unsigned int size) 115{ 116 struct tegra_bo *bo; 117 int err; 118 119 bo = kzalloc(sizeof(*bo), GFP_KERNEL); 120 if (!bo) 121 return ERR_PTR(-ENOMEM); 122 123 host1x_bo_init(&bo->base, &tegra_bo_ops); 124 size = round_up(size, PAGE_SIZE); 125 126 bo->vaddr = dma_alloc_writecombine(drm->dev, size, &bo->paddr, 127 GFP_KERNEL | __GFP_NOWARN); 128 if (!bo->vaddr) { 129 dev_err(drm->dev, "failed to allocate buffer with size %u\n", 130 size); 131 err = -ENOMEM; 132 goto err_dma; 133 } 134 135 err = drm_gem_object_init(drm, &bo->gem, size); 136 if (err) 137 goto err_init; 138 139 err = drm_gem_create_mmap_offset(&bo->gem); 140 if (err) 141 goto err_mmap; 142 143 return bo; 144 145err_mmap: 146 drm_gem_object_release(&bo->gem); 147err_init: 148 tegra_bo_destroy(drm, bo); 149err_dma: 150 kfree(bo); 151 152 return ERR_PTR(err); 153 154} 155 156struct tegra_bo *tegra_bo_create_with_handle(struct drm_file *file, 157 struct drm_device *drm, 158 unsigned int size, 159 unsigned int *handle) 160{ 161 struct tegra_bo *bo; 162 int ret; 163 164 bo = tegra_bo_create(drm, size); 165 if (IS_ERR(bo)) 166 return bo; 167 168 ret = drm_gem_handle_create(file, &bo->gem, handle); 169 if (ret) 170 goto err; 171 172 drm_gem_object_unreference_unlocked(&bo->gem); 173 174 return bo; 175 176err: 177 tegra_bo_free_object(&bo->gem); 178 return ERR_PTR(ret); 179} 180 181void tegra_bo_free_object(struct drm_gem_object *gem) 182{ 183 struct tegra_bo *bo = to_tegra_bo(gem); 184 185 if (gem->map_list.map) 186 drm_gem_free_mmap_offset(gem); 187 188 drm_gem_object_release(gem); 189 tegra_bo_destroy(gem->dev, bo); 190 191 kfree(bo); 192} 193 194int tegra_bo_dumb_create(struct drm_file *file, struct drm_device *drm, 195 struct drm_mode_create_dumb *args) 196{ 197 int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8); 198 struct tegra_bo *bo; 199 200 if (args->pitch < min_pitch) 201 args->pitch = min_pitch; 202 203 if (args->size < args->pitch * args->height) 204 args->size = args->pitch * args->height; 205 206 bo = tegra_bo_create_with_handle(file, drm, args->size, 207 &args->handle); 208 if (IS_ERR(bo)) 209 return PTR_ERR(bo); 210 211 return 0; 212} 213 214int tegra_bo_dumb_map_offset(struct drm_file *file, struct drm_device *drm, 215 uint32_t handle, uint64_t *offset) 216{ 217 struct drm_gem_object *gem; 218 struct tegra_bo *bo; 219 220 mutex_lock(&drm->struct_mutex); 221 222 gem = drm_gem_object_lookup(drm, file, handle); 223 if (!gem) { 224 dev_err(drm->dev, "failed to lookup GEM object\n"); 225 mutex_unlock(&drm->struct_mutex); 226 return -EINVAL; 227 } 228 229 bo = to_tegra_bo(gem); 230 231 *offset = tegra_bo_get_mmap_offset(bo); 232 233 drm_gem_object_unreference(gem); 234 235 mutex_unlock(&drm->struct_mutex); 236 237 return 0; 238} 239 240const struct vm_operations_struct tegra_bo_vm_ops = { 241 .open = drm_gem_vm_open, 242 .close = drm_gem_vm_close, 243}; 244 245int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma) 246{ 247 struct drm_gem_object *gem; 248 struct tegra_bo *bo; 249 int ret; 250 251 ret = drm_gem_mmap(file, vma); 252 if (ret) 253 return ret; 254 255 gem = vma->vm_private_data; 256 bo = to_tegra_bo(gem); 257 258 ret = remap_pfn_range(vma, vma->vm_start, bo->paddr >> PAGE_SHIFT, 259 vma->vm_end - vma->vm_start, vma->vm_page_prot); 260 if (ret) 261 drm_gem_vm_close(vma); 262 263 return ret; 264} 265 266int tegra_bo_dumb_destroy(struct drm_file *file, struct drm_device *drm, 267 unsigned int handle) 268{ 269 return drm_gem_handle_delete(file, handle); 270}