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 v4.18 533 lines 13 kB view raw
1/* 2 * This program is free software; you can redistribute it and/or modify 3 * it under the terms of the GNU General Public License as published by 4 * the Free Software Foundation; either version 2 of the License, or 5 * (at your option) any later version. 6 */ 7 8#include "bochs.h" 9 10static void bochs_ttm_placement(struct bochs_bo *bo, int domain); 11 12/* ---------------------------------------------------------------------- */ 13 14static inline struct bochs_device *bochs_bdev(struct ttm_bo_device *bd) 15{ 16 return container_of(bd, struct bochs_device, ttm.bdev); 17} 18 19static int bochs_ttm_mem_global_init(struct drm_global_reference *ref) 20{ 21 return ttm_mem_global_init(ref->object); 22} 23 24static void bochs_ttm_mem_global_release(struct drm_global_reference *ref) 25{ 26 ttm_mem_global_release(ref->object); 27} 28 29static int bochs_ttm_global_init(struct bochs_device *bochs) 30{ 31 struct drm_global_reference *global_ref; 32 int r; 33 34 global_ref = &bochs->ttm.mem_global_ref; 35 global_ref->global_type = DRM_GLOBAL_TTM_MEM; 36 global_ref->size = sizeof(struct ttm_mem_global); 37 global_ref->init = &bochs_ttm_mem_global_init; 38 global_ref->release = &bochs_ttm_mem_global_release; 39 r = drm_global_item_ref(global_ref); 40 if (r != 0) { 41 DRM_ERROR("Failed setting up TTM memory accounting " 42 "subsystem.\n"); 43 return r; 44 } 45 46 bochs->ttm.bo_global_ref.mem_glob = 47 bochs->ttm.mem_global_ref.object; 48 global_ref = &bochs->ttm.bo_global_ref.ref; 49 global_ref->global_type = DRM_GLOBAL_TTM_BO; 50 global_ref->size = sizeof(struct ttm_bo_global); 51 global_ref->init = &ttm_bo_global_init; 52 global_ref->release = &ttm_bo_global_release; 53 r = drm_global_item_ref(global_ref); 54 if (r != 0) { 55 DRM_ERROR("Failed setting up TTM BO subsystem.\n"); 56 drm_global_item_unref(&bochs->ttm.mem_global_ref); 57 return r; 58 } 59 60 return 0; 61} 62 63static void bochs_ttm_global_release(struct bochs_device *bochs) 64{ 65 if (bochs->ttm.mem_global_ref.release == NULL) 66 return; 67 68 drm_global_item_unref(&bochs->ttm.bo_global_ref.ref); 69 drm_global_item_unref(&bochs->ttm.mem_global_ref); 70 bochs->ttm.mem_global_ref.release = NULL; 71} 72 73 74static void bochs_bo_ttm_destroy(struct ttm_buffer_object *tbo) 75{ 76 struct bochs_bo *bo; 77 78 bo = container_of(tbo, struct bochs_bo, bo); 79 drm_gem_object_release(&bo->gem); 80 kfree(bo); 81} 82 83static bool bochs_ttm_bo_is_bochs_bo(struct ttm_buffer_object *bo) 84{ 85 if (bo->destroy == &bochs_bo_ttm_destroy) 86 return true; 87 return false; 88} 89 90static int bochs_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, 91 struct ttm_mem_type_manager *man) 92{ 93 switch (type) { 94 case TTM_PL_SYSTEM: 95 man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; 96 man->available_caching = TTM_PL_MASK_CACHING; 97 man->default_caching = TTM_PL_FLAG_CACHED; 98 break; 99 case TTM_PL_VRAM: 100 man->func = &ttm_bo_manager_func; 101 man->flags = TTM_MEMTYPE_FLAG_FIXED | 102 TTM_MEMTYPE_FLAG_MAPPABLE; 103 man->available_caching = TTM_PL_FLAG_UNCACHED | 104 TTM_PL_FLAG_WC; 105 man->default_caching = TTM_PL_FLAG_WC; 106 break; 107 default: 108 DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); 109 return -EINVAL; 110 } 111 return 0; 112} 113 114static void 115bochs_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl) 116{ 117 struct bochs_bo *bochsbo = bochs_bo(bo); 118 119 if (!bochs_ttm_bo_is_bochs_bo(bo)) 120 return; 121 122 bochs_ttm_placement(bochsbo, TTM_PL_FLAG_SYSTEM); 123 *pl = bochsbo->placement; 124} 125 126static int bochs_bo_verify_access(struct ttm_buffer_object *bo, 127 struct file *filp) 128{ 129 struct bochs_bo *bochsbo = bochs_bo(bo); 130 131 return drm_vma_node_verify_access(&bochsbo->gem.vma_node, 132 filp->private_data); 133} 134 135static int bochs_ttm_io_mem_reserve(struct ttm_bo_device *bdev, 136 struct ttm_mem_reg *mem) 137{ 138 struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; 139 struct bochs_device *bochs = bochs_bdev(bdev); 140 141 mem->bus.addr = NULL; 142 mem->bus.offset = 0; 143 mem->bus.size = mem->num_pages << PAGE_SHIFT; 144 mem->bus.base = 0; 145 mem->bus.is_iomem = false; 146 if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE)) 147 return -EINVAL; 148 switch (mem->mem_type) { 149 case TTM_PL_SYSTEM: 150 /* system memory */ 151 return 0; 152 case TTM_PL_VRAM: 153 mem->bus.offset = mem->start << PAGE_SHIFT; 154 mem->bus.base = bochs->fb_base; 155 mem->bus.is_iomem = true; 156 break; 157 default: 158 return -EINVAL; 159 break; 160 } 161 return 0; 162} 163 164static void bochs_ttm_io_mem_free(struct ttm_bo_device *bdev, 165 struct ttm_mem_reg *mem) 166{ 167} 168 169static void bochs_ttm_backend_destroy(struct ttm_tt *tt) 170{ 171 ttm_tt_fini(tt); 172 kfree(tt); 173} 174 175static struct ttm_backend_func bochs_tt_backend_func = { 176 .destroy = &bochs_ttm_backend_destroy, 177}; 178 179static struct ttm_tt *bochs_ttm_tt_create(struct ttm_buffer_object *bo, 180 uint32_t page_flags) 181{ 182 struct ttm_tt *tt; 183 184 tt = kzalloc(sizeof(struct ttm_tt), GFP_KERNEL); 185 if (tt == NULL) 186 return NULL; 187 tt->func = &bochs_tt_backend_func; 188 if (ttm_tt_init(tt, bo, page_flags)) { 189 kfree(tt); 190 return NULL; 191 } 192 return tt; 193} 194 195static struct ttm_bo_driver bochs_bo_driver = { 196 .ttm_tt_create = bochs_ttm_tt_create, 197 .init_mem_type = bochs_bo_init_mem_type, 198 .eviction_valuable = ttm_bo_eviction_valuable, 199 .evict_flags = bochs_bo_evict_flags, 200 .move = NULL, 201 .verify_access = bochs_bo_verify_access, 202 .io_mem_reserve = &bochs_ttm_io_mem_reserve, 203 .io_mem_free = &bochs_ttm_io_mem_free, 204}; 205 206int bochs_mm_init(struct bochs_device *bochs) 207{ 208 struct ttm_bo_device *bdev = &bochs->ttm.bdev; 209 int ret; 210 211 ret = bochs_ttm_global_init(bochs); 212 if (ret) 213 return ret; 214 215 ret = ttm_bo_device_init(&bochs->ttm.bdev, 216 bochs->ttm.bo_global_ref.ref.object, 217 &bochs_bo_driver, 218 bochs->dev->anon_inode->i_mapping, 219 DRM_FILE_PAGE_OFFSET, 220 true); 221 if (ret) { 222 DRM_ERROR("Error initialising bo driver; %d\n", ret); 223 return ret; 224 } 225 226 ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM, 227 bochs->fb_size >> PAGE_SHIFT); 228 if (ret) { 229 DRM_ERROR("Failed ttm VRAM init: %d\n", ret); 230 return ret; 231 } 232 233 bochs->ttm.initialized = true; 234 return 0; 235} 236 237void bochs_mm_fini(struct bochs_device *bochs) 238{ 239 if (!bochs->ttm.initialized) 240 return; 241 242 ttm_bo_device_release(&bochs->ttm.bdev); 243 bochs_ttm_global_release(bochs); 244 bochs->ttm.initialized = false; 245} 246 247static void bochs_ttm_placement(struct bochs_bo *bo, int domain) 248{ 249 unsigned i; 250 u32 c = 0; 251 bo->placement.placement = bo->placements; 252 bo->placement.busy_placement = bo->placements; 253 if (domain & TTM_PL_FLAG_VRAM) { 254 bo->placements[c++].flags = TTM_PL_FLAG_WC 255 | TTM_PL_FLAG_UNCACHED 256 | TTM_PL_FLAG_VRAM; 257 } 258 if (domain & TTM_PL_FLAG_SYSTEM) { 259 bo->placements[c++].flags = TTM_PL_MASK_CACHING 260 | TTM_PL_FLAG_SYSTEM; 261 } 262 if (!c) { 263 bo->placements[c++].flags = TTM_PL_MASK_CACHING 264 | TTM_PL_FLAG_SYSTEM; 265 } 266 for (i = 0; i < c; ++i) { 267 bo->placements[i].fpfn = 0; 268 bo->placements[i].lpfn = 0; 269 } 270 bo->placement.num_placement = c; 271 bo->placement.num_busy_placement = c; 272} 273 274static inline u64 bochs_bo_gpu_offset(struct bochs_bo *bo) 275{ 276 return bo->bo.offset; 277} 278 279int bochs_bo_pin(struct bochs_bo *bo, u32 pl_flag, u64 *gpu_addr) 280{ 281 struct ttm_operation_ctx ctx = { false, false }; 282 int i, ret; 283 284 if (bo->pin_count) { 285 bo->pin_count++; 286 if (gpu_addr) 287 *gpu_addr = bochs_bo_gpu_offset(bo); 288 return 0; 289 } 290 291 bochs_ttm_placement(bo, pl_flag); 292 for (i = 0; i < bo->placement.num_placement; i++) 293 bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; 294 ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx); 295 if (ret) 296 return ret; 297 298 bo->pin_count = 1; 299 if (gpu_addr) 300 *gpu_addr = bochs_bo_gpu_offset(bo); 301 return 0; 302} 303 304int bochs_bo_unpin(struct bochs_bo *bo) 305{ 306 struct ttm_operation_ctx ctx = { false, false }; 307 int i, ret; 308 309 if (!bo->pin_count) { 310 DRM_ERROR("unpin bad %p\n", bo); 311 return 0; 312 } 313 bo->pin_count--; 314 315 if (bo->pin_count) 316 return 0; 317 318 for (i = 0; i < bo->placement.num_placement; i++) 319 bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT; 320 ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx); 321 if (ret) 322 return ret; 323 324 return 0; 325} 326 327int bochs_mmap(struct file *filp, struct vm_area_struct *vma) 328{ 329 struct drm_file *file_priv; 330 struct bochs_device *bochs; 331 332 if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET)) 333 return -EINVAL; 334 335 file_priv = filp->private_data; 336 bochs = file_priv->minor->dev->dev_private; 337 return ttm_bo_mmap(filp, vma, &bochs->ttm.bdev); 338} 339 340/* ---------------------------------------------------------------------- */ 341 342static int bochs_bo_create(struct drm_device *dev, int size, int align, 343 uint32_t flags, struct bochs_bo **pbochsbo) 344{ 345 struct bochs_device *bochs = dev->dev_private; 346 struct bochs_bo *bochsbo; 347 size_t acc_size; 348 int ret; 349 350 bochsbo = kzalloc(sizeof(struct bochs_bo), GFP_KERNEL); 351 if (!bochsbo) 352 return -ENOMEM; 353 354 ret = drm_gem_object_init(dev, &bochsbo->gem, size); 355 if (ret) { 356 kfree(bochsbo); 357 return ret; 358 } 359 360 bochsbo->bo.bdev = &bochs->ttm.bdev; 361 bochsbo->bo.bdev->dev_mapping = dev->anon_inode->i_mapping; 362 363 bochs_ttm_placement(bochsbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); 364 365 acc_size = ttm_bo_dma_acc_size(&bochs->ttm.bdev, size, 366 sizeof(struct bochs_bo)); 367 368 ret = ttm_bo_init(&bochs->ttm.bdev, &bochsbo->bo, size, 369 ttm_bo_type_device, &bochsbo->placement, 370 align >> PAGE_SHIFT, false, acc_size, 371 NULL, NULL, bochs_bo_ttm_destroy); 372 if (ret) 373 return ret; 374 375 *pbochsbo = bochsbo; 376 return 0; 377} 378 379int bochs_gem_create(struct drm_device *dev, u32 size, bool iskernel, 380 struct drm_gem_object **obj) 381{ 382 struct bochs_bo *bochsbo; 383 int ret; 384 385 *obj = NULL; 386 387 size = PAGE_ALIGN(size); 388 if (size == 0) 389 return -EINVAL; 390 391 ret = bochs_bo_create(dev, size, 0, 0, &bochsbo); 392 if (ret) { 393 if (ret != -ERESTARTSYS) 394 DRM_ERROR("failed to allocate GEM object\n"); 395 return ret; 396 } 397 *obj = &bochsbo->gem; 398 return 0; 399} 400 401int bochs_dumb_create(struct drm_file *file, struct drm_device *dev, 402 struct drm_mode_create_dumb *args) 403{ 404 struct drm_gem_object *gobj; 405 u32 handle; 406 int ret; 407 408 args->pitch = args->width * ((args->bpp + 7) / 8); 409 args->size = args->pitch * args->height; 410 411 ret = bochs_gem_create(dev, args->size, false, 412 &gobj); 413 if (ret) 414 return ret; 415 416 ret = drm_gem_handle_create(file, gobj, &handle); 417 drm_gem_object_unreference_unlocked(gobj); 418 if (ret) 419 return ret; 420 421 args->handle = handle; 422 return 0; 423} 424 425static void bochs_bo_unref(struct bochs_bo **bo) 426{ 427 struct ttm_buffer_object *tbo; 428 429 if ((*bo) == NULL) 430 return; 431 432 tbo = &((*bo)->bo); 433 ttm_bo_unref(&tbo); 434 *bo = NULL; 435} 436 437void bochs_gem_free_object(struct drm_gem_object *obj) 438{ 439 struct bochs_bo *bochs_bo = gem_to_bochs_bo(obj); 440 441 bochs_bo_unref(&bochs_bo); 442} 443 444int bochs_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev, 445 uint32_t handle, uint64_t *offset) 446{ 447 struct drm_gem_object *obj; 448 struct bochs_bo *bo; 449 450 obj = drm_gem_object_lookup(file, handle); 451 if (obj == NULL) 452 return -ENOENT; 453 454 bo = gem_to_bochs_bo(obj); 455 *offset = bochs_bo_mmap_offset(bo); 456 457 drm_gem_object_unreference_unlocked(obj); 458 return 0; 459} 460 461/* ---------------------------------------------------------------------- */ 462 463static void bochs_user_framebuffer_destroy(struct drm_framebuffer *fb) 464{ 465 struct bochs_framebuffer *bochs_fb = to_bochs_framebuffer(fb); 466 467 drm_gem_object_unreference_unlocked(bochs_fb->obj); 468 drm_framebuffer_cleanup(fb); 469 kfree(fb); 470} 471 472static const struct drm_framebuffer_funcs bochs_fb_funcs = { 473 .destroy = bochs_user_framebuffer_destroy, 474}; 475 476int bochs_framebuffer_init(struct drm_device *dev, 477 struct bochs_framebuffer *gfb, 478 const struct drm_mode_fb_cmd2 *mode_cmd, 479 struct drm_gem_object *obj) 480{ 481 int ret; 482 483 drm_helper_mode_fill_fb_struct(dev, &gfb->base, mode_cmd); 484 gfb->obj = obj; 485 ret = drm_framebuffer_init(dev, &gfb->base, &bochs_fb_funcs); 486 if (ret) { 487 DRM_ERROR("drm_framebuffer_init failed: %d\n", ret); 488 return ret; 489 } 490 return 0; 491} 492 493static struct drm_framebuffer * 494bochs_user_framebuffer_create(struct drm_device *dev, 495 struct drm_file *filp, 496 const struct drm_mode_fb_cmd2 *mode_cmd) 497{ 498 struct drm_gem_object *obj; 499 struct bochs_framebuffer *bochs_fb; 500 int ret; 501 502 DRM_DEBUG_DRIVER("%dx%d, format %c%c%c%c\n", 503 mode_cmd->width, mode_cmd->height, 504 (mode_cmd->pixel_format) & 0xff, 505 (mode_cmd->pixel_format >> 8) & 0xff, 506 (mode_cmd->pixel_format >> 16) & 0xff, 507 (mode_cmd->pixel_format >> 24) & 0xff); 508 509 if (mode_cmd->pixel_format != DRM_FORMAT_XRGB8888) 510 return ERR_PTR(-ENOENT); 511 512 obj = drm_gem_object_lookup(filp, mode_cmd->handles[0]); 513 if (obj == NULL) 514 return ERR_PTR(-ENOENT); 515 516 bochs_fb = kzalloc(sizeof(*bochs_fb), GFP_KERNEL); 517 if (!bochs_fb) { 518 drm_gem_object_unreference_unlocked(obj); 519 return ERR_PTR(-ENOMEM); 520 } 521 522 ret = bochs_framebuffer_init(dev, bochs_fb, mode_cmd, obj); 523 if (ret) { 524 drm_gem_object_unreference_unlocked(obj); 525 kfree(bochs_fb); 526 return ERR_PTR(ret); 527 } 528 return &bochs_fb->base; 529} 530 531const struct drm_mode_config_funcs bochs_mode_funcs = { 532 .fb_create = bochs_user_framebuffer_create, 533};