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 v5.1 343 lines 8.8 kB view raw
1/* 2 * Copyright 2012 Red Hat Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the 6 * "Software"), to deal in the Software without restriction, including 7 * without limitation the rights to use, copy, modify, merge, publish, 8 * distribute, sub license, and/or sell copies of the Software, and to 9 * permit persons to whom the Software is furnished to do so, subject to 10 * the following conditions: 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 15 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 16 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 17 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 18 * USE OR OTHER DEALINGS IN THE SOFTWARE. 19 * 20 * The above copyright notice and this permission notice (including the 21 * next paragraph) shall be included in all copies or substantial portions 22 * of the Software. 23 * 24 */ 25/* 26 * Authors: Dave Airlie <airlied@redhat.com> 27 */ 28#include <drm/drmP.h> 29#include <drm/ttm/ttm_page_alloc.h> 30 31#include "cirrus_drv.h" 32 33static inline struct cirrus_device * 34cirrus_bdev(struct ttm_bo_device *bd) 35{ 36 return container_of(bd, struct cirrus_device, ttm.bdev); 37} 38 39static void cirrus_bo_ttm_destroy(struct ttm_buffer_object *tbo) 40{ 41 struct cirrus_bo *bo; 42 43 bo = container_of(tbo, struct cirrus_bo, bo); 44 45 drm_gem_object_release(&bo->gem); 46 kfree(bo); 47} 48 49static bool cirrus_ttm_bo_is_cirrus_bo(struct ttm_buffer_object *bo) 50{ 51 if (bo->destroy == &cirrus_bo_ttm_destroy) 52 return true; 53 return false; 54} 55 56static int 57cirrus_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, 58 struct ttm_mem_type_manager *man) 59{ 60 switch (type) { 61 case TTM_PL_SYSTEM: 62 man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; 63 man->available_caching = TTM_PL_MASK_CACHING; 64 man->default_caching = TTM_PL_FLAG_CACHED; 65 break; 66 case TTM_PL_VRAM: 67 man->func = &ttm_bo_manager_func; 68 man->flags = TTM_MEMTYPE_FLAG_FIXED | 69 TTM_MEMTYPE_FLAG_MAPPABLE; 70 man->available_caching = TTM_PL_FLAG_UNCACHED | 71 TTM_PL_FLAG_WC; 72 man->default_caching = TTM_PL_FLAG_WC; 73 break; 74 default: 75 DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); 76 return -EINVAL; 77 } 78 return 0; 79} 80 81static void 82cirrus_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl) 83{ 84 struct cirrus_bo *cirrusbo = cirrus_bo(bo); 85 86 if (!cirrus_ttm_bo_is_cirrus_bo(bo)) 87 return; 88 89 cirrus_ttm_placement(cirrusbo, TTM_PL_FLAG_SYSTEM); 90 *pl = cirrusbo->placement; 91} 92 93static int cirrus_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp) 94{ 95 struct cirrus_bo *cirrusbo = cirrus_bo(bo); 96 97 return drm_vma_node_verify_access(&cirrusbo->gem.vma_node, 98 filp->private_data); 99} 100 101static int cirrus_ttm_io_mem_reserve(struct ttm_bo_device *bdev, 102 struct ttm_mem_reg *mem) 103{ 104 struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; 105 struct cirrus_device *cirrus = cirrus_bdev(bdev); 106 107 mem->bus.addr = NULL; 108 mem->bus.offset = 0; 109 mem->bus.size = mem->num_pages << PAGE_SHIFT; 110 mem->bus.base = 0; 111 mem->bus.is_iomem = false; 112 if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE)) 113 return -EINVAL; 114 switch (mem->mem_type) { 115 case TTM_PL_SYSTEM: 116 /* system memory */ 117 return 0; 118 case TTM_PL_VRAM: 119 mem->bus.offset = mem->start << PAGE_SHIFT; 120 mem->bus.base = pci_resource_start(cirrus->dev->pdev, 0); 121 mem->bus.is_iomem = true; 122 break; 123 default: 124 return -EINVAL; 125 break; 126 } 127 return 0; 128} 129 130static void cirrus_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) 131{ 132} 133 134static void cirrus_ttm_backend_destroy(struct ttm_tt *tt) 135{ 136 ttm_tt_fini(tt); 137 kfree(tt); 138} 139 140static struct ttm_backend_func cirrus_tt_backend_func = { 141 .destroy = &cirrus_ttm_backend_destroy, 142}; 143 144 145static struct ttm_tt *cirrus_ttm_tt_create(struct ttm_buffer_object *bo, 146 uint32_t page_flags) 147{ 148 struct ttm_tt *tt; 149 150 tt = kzalloc(sizeof(struct ttm_tt), GFP_KERNEL); 151 if (tt == NULL) 152 return NULL; 153 tt->func = &cirrus_tt_backend_func; 154 if (ttm_tt_init(tt, bo, page_flags)) { 155 kfree(tt); 156 return NULL; 157 } 158 return tt; 159} 160 161struct ttm_bo_driver cirrus_bo_driver = { 162 .ttm_tt_create = cirrus_ttm_tt_create, 163 .init_mem_type = cirrus_bo_init_mem_type, 164 .eviction_valuable = ttm_bo_eviction_valuable, 165 .evict_flags = cirrus_bo_evict_flags, 166 .move = NULL, 167 .verify_access = cirrus_bo_verify_access, 168 .io_mem_reserve = &cirrus_ttm_io_mem_reserve, 169 .io_mem_free = &cirrus_ttm_io_mem_free, 170}; 171 172int cirrus_mm_init(struct cirrus_device *cirrus) 173{ 174 int ret; 175 struct drm_device *dev = cirrus->dev; 176 struct ttm_bo_device *bdev = &cirrus->ttm.bdev; 177 178 ret = ttm_bo_device_init(&cirrus->ttm.bdev, 179 &cirrus_bo_driver, 180 dev->anon_inode->i_mapping, 181 DRM_FILE_PAGE_OFFSET, 182 true); 183 if (ret) { 184 DRM_ERROR("Error initialising bo driver; %d\n", ret); 185 return ret; 186 } 187 188 ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM, 189 cirrus->mc.vram_size >> PAGE_SHIFT); 190 if (ret) { 191 DRM_ERROR("Failed ttm VRAM init: %d\n", ret); 192 return ret; 193 } 194 195 arch_io_reserve_memtype_wc(pci_resource_start(dev->pdev, 0), 196 pci_resource_len(dev->pdev, 0)); 197 198 cirrus->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0), 199 pci_resource_len(dev->pdev, 0)); 200 201 cirrus->mm_inited = true; 202 return 0; 203} 204 205void cirrus_mm_fini(struct cirrus_device *cirrus) 206{ 207 struct drm_device *dev = cirrus->dev; 208 209 if (!cirrus->mm_inited) 210 return; 211 212 ttm_bo_device_release(&cirrus->ttm.bdev); 213 214 arch_phys_wc_del(cirrus->fb_mtrr); 215 cirrus->fb_mtrr = 0; 216 arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0), 217 pci_resource_len(dev->pdev, 0)); 218} 219 220void cirrus_ttm_placement(struct cirrus_bo *bo, int domain) 221{ 222 u32 c = 0; 223 unsigned i; 224 bo->placement.placement = bo->placements; 225 bo->placement.busy_placement = bo->placements; 226 if (domain & TTM_PL_FLAG_VRAM) 227 bo->placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM; 228 if (domain & TTM_PL_FLAG_SYSTEM) 229 bo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; 230 if (!c) 231 bo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; 232 bo->placement.num_placement = c; 233 bo->placement.num_busy_placement = c; 234 for (i = 0; i < c; ++i) { 235 bo->placements[i].fpfn = 0; 236 bo->placements[i].lpfn = 0; 237 } 238} 239 240int cirrus_bo_create(struct drm_device *dev, int size, int align, 241 uint32_t flags, struct cirrus_bo **pcirrusbo) 242{ 243 struct cirrus_device *cirrus = dev->dev_private; 244 struct cirrus_bo *cirrusbo; 245 size_t acc_size; 246 int ret; 247 248 cirrusbo = kzalloc(sizeof(struct cirrus_bo), GFP_KERNEL); 249 if (!cirrusbo) 250 return -ENOMEM; 251 252 ret = drm_gem_object_init(dev, &cirrusbo->gem, size); 253 if (ret) { 254 kfree(cirrusbo); 255 return ret; 256 } 257 258 cirrusbo->bo.bdev = &cirrus->ttm.bdev; 259 260 cirrus_ttm_placement(cirrusbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); 261 262 acc_size = ttm_bo_dma_acc_size(&cirrus->ttm.bdev, size, 263 sizeof(struct cirrus_bo)); 264 265 ret = ttm_bo_init(&cirrus->ttm.bdev, &cirrusbo->bo, size, 266 ttm_bo_type_device, &cirrusbo->placement, 267 align >> PAGE_SHIFT, false, acc_size, 268 NULL, NULL, cirrus_bo_ttm_destroy); 269 if (ret) 270 return ret; 271 272 *pcirrusbo = cirrusbo; 273 return 0; 274} 275 276static inline u64 cirrus_bo_gpu_offset(struct cirrus_bo *bo) 277{ 278 return bo->bo.offset; 279} 280 281int cirrus_bo_pin(struct cirrus_bo *bo, u32 pl_flag, u64 *gpu_addr) 282{ 283 struct ttm_operation_ctx ctx = { false, false }; 284 int i, ret; 285 286 if (bo->pin_count) { 287 bo->pin_count++; 288 if (gpu_addr) 289 *gpu_addr = cirrus_bo_gpu_offset(bo); 290 } 291 292 cirrus_ttm_placement(bo, pl_flag); 293 for (i = 0; i < bo->placement.num_placement; i++) 294 bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; 295 ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx); 296 if (ret) 297 return ret; 298 299 bo->pin_count = 1; 300 if (gpu_addr) 301 *gpu_addr = cirrus_bo_gpu_offset(bo); 302 return 0; 303} 304 305int cirrus_bo_push_sysram(struct cirrus_bo *bo) 306{ 307 struct ttm_operation_ctx ctx = { false, false }; 308 int i, ret; 309 if (!bo->pin_count) { 310 DRM_ERROR("unpin bad %p\n", bo); 311 return 0; 312 } 313 bo->pin_count--; 314 if (bo->pin_count) 315 return 0; 316 317 if (bo->kmap.virtual) 318 ttm_bo_kunmap(&bo->kmap); 319 320 cirrus_ttm_placement(bo, TTM_PL_FLAG_SYSTEM); 321 for (i = 0; i < bo->placement.num_placement ; i++) 322 bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; 323 324 ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx); 325 if (ret) { 326 DRM_ERROR("pushing to VRAM failed\n"); 327 return ret; 328 } 329 return 0; 330} 331 332int cirrus_mmap(struct file *filp, struct vm_area_struct *vma) 333{ 334 struct drm_file *file_priv; 335 struct cirrus_device *cirrus; 336 337 if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET)) 338 return -EINVAL; 339 340 file_priv = filp->private_data; 341 cirrus = file_priv->minor->dev->dev_private; 342 return ttm_bo_mmap(filp, vma, &cirrus->ttm.bdev); 343}