Annotation of src/sys/external/bsd/drm2/dist/drm/vmwgfx/vmwgfx_resource.c, Revision 1.1.1.1.2.2
1.1.1.1.2.2! riastrad 1: /**************************************************************************
! 2: *
! 3: * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
! 4: * All Rights Reserved.
! 5: *
! 6: * Permission is hereby granted, free of charge, to any person obtaining a
! 7: * copy of this software and associated documentation files (the
! 8: * "Software"), to deal in the Software without restriction, including
! 9: * without limitation the rights to use, copy, modify, merge, publish,
! 10: * distribute, sub license, and/or sell copies of the Software, and to
! 11: * permit persons to whom the Software is furnished to do so, subject to
! 12: * the following conditions:
! 13: *
! 14: * The above copyright notice and this permission notice (including the
! 15: * next paragraph) shall be included in all copies or substantial portions
! 16: * of the Software.
! 17: *
! 18: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
! 19: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
! 20: * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
! 21: * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
! 22: * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
! 23: * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
! 24: * USE OR OTHER DEALINGS IN THE SOFTWARE.
! 25: *
! 26: **************************************************************************/
! 27:
! 28: #include "vmwgfx_drv.h"
! 29: #include <drm/vmwgfx_drm.h>
! 30: #include <drm/ttm/ttm_object.h>
! 31: #include <drm/ttm/ttm_placement.h>
! 32: #include <drm/drmP.h>
! 33: #include "vmwgfx_resource_priv.h"
! 34:
! 35: struct vmw_user_dma_buffer {
! 36: struct ttm_base_object base;
! 37: struct vmw_dma_buffer dma;
! 38: };
! 39:
! 40: struct vmw_bo_user_rep {
! 41: uint32_t handle;
! 42: uint64_t map_handle;
! 43: };
! 44:
! 45: struct vmw_stream {
! 46: struct vmw_resource res;
! 47: uint32_t stream_id;
! 48: };
! 49:
! 50: struct vmw_user_stream {
! 51: struct ttm_base_object base;
! 52: struct vmw_stream stream;
! 53: };
! 54:
! 55:
! 56: static uint64_t vmw_user_stream_size;
! 57:
! 58: static const struct vmw_res_func vmw_stream_func = {
! 59: .res_type = vmw_res_stream,
! 60: .needs_backup = false,
! 61: .may_evict = false,
! 62: .type_name = "video streams",
! 63: .backup_placement = NULL,
! 64: .create = NULL,
! 65: .destroy = NULL,
! 66: .bind = NULL,
! 67: .unbind = NULL
! 68: };
! 69:
! 70: static inline struct vmw_dma_buffer *
! 71: vmw_dma_buffer(struct ttm_buffer_object *bo)
! 72: {
! 73: return container_of(bo, struct vmw_dma_buffer, base);
! 74: }
! 75:
! 76: static inline struct vmw_user_dma_buffer *
! 77: vmw_user_dma_buffer(struct ttm_buffer_object *bo)
! 78: {
! 79: struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo);
! 80: return container_of(vmw_bo, struct vmw_user_dma_buffer, dma);
! 81: }
! 82:
! 83: struct vmw_resource *vmw_resource_reference(struct vmw_resource *res)
! 84: {
! 85: kref_get(&res->kref);
! 86: return res;
! 87: }
! 88:
! 89:
! 90: /**
! 91: * vmw_resource_release_id - release a resource id to the id manager.
! 92: *
! 93: * @res: Pointer to the resource.
! 94: *
! 95: * Release the resource id to the resource id manager and set it to -1
! 96: */
! 97: void vmw_resource_release_id(struct vmw_resource *res)
! 98: {
! 99: struct vmw_private *dev_priv = res->dev_priv;
! 100: struct idr *idr = &dev_priv->res_idr[res->func->res_type];
! 101:
! 102: write_lock(&dev_priv->resource_lock);
! 103: if (res->id != -1)
! 104: idr_remove(idr, res->id);
! 105: res->id = -1;
! 106: write_unlock(&dev_priv->resource_lock);
! 107: }
! 108:
! 109: static void vmw_resource_release(struct kref *kref)
! 110: {
! 111: struct vmw_resource *res =
! 112: container_of(kref, struct vmw_resource, kref);
! 113: struct vmw_private *dev_priv = res->dev_priv;
! 114: int id;
! 115: struct idr *idr = &dev_priv->res_idr[res->func->res_type];
! 116:
! 117: res->avail = false;
! 118: list_del_init(&res->lru_head);
! 119: write_unlock(&dev_priv->resource_lock);
! 120: if (res->backup) {
! 121: struct ttm_buffer_object *bo = &res->backup->base;
! 122:
! 123: ttm_bo_reserve(bo, false, false, false, 0);
! 124: if (!list_empty(&res->mob_head) &&
! 125: res->func->unbind != NULL) {
! 126: struct ttm_validate_buffer val_buf;
! 127:
! 128: val_buf.bo = bo;
! 129: res->func->unbind(res, false, &val_buf);
! 130: }
! 131: res->backup_dirty = false;
! 132: list_del_init(&res->mob_head);
! 133: ttm_bo_unreserve(bo);
! 134: vmw_dmabuf_unreference(&res->backup);
! 135: }
! 136:
! 137: if (likely(res->hw_destroy != NULL))
! 138: res->hw_destroy(res);
! 139:
! 140: id = res->id;
! 141: if (res->res_free != NULL)
! 142: res->res_free(res);
! 143: else
! 144: kfree(res);
! 145:
! 146: write_lock(&dev_priv->resource_lock);
! 147:
! 148: if (id != -1)
! 149: idr_remove(idr, id);
! 150: }
! 151:
! 152: void vmw_resource_unreference(struct vmw_resource **p_res)
! 153: {
! 154: struct vmw_resource *res = *p_res;
! 155: struct vmw_private *dev_priv = res->dev_priv;
! 156:
! 157: *p_res = NULL;
! 158: write_lock(&dev_priv->resource_lock);
! 159: kref_put(&res->kref, vmw_resource_release);
! 160: write_unlock(&dev_priv->resource_lock);
! 161: }
! 162:
! 163:
! 164: /**
! 165: * vmw_resource_alloc_id - release a resource id to the id manager.
! 166: *
! 167: * @res: Pointer to the resource.
! 168: *
! 169: * Allocate the lowest free resource from the resource manager, and set
! 170: * @res->id to that id. Returns 0 on success and -ENOMEM on failure.
! 171: */
! 172: int vmw_resource_alloc_id(struct vmw_resource *res)
! 173: {
! 174: struct vmw_private *dev_priv = res->dev_priv;
! 175: int ret;
! 176: struct idr *idr = &dev_priv->res_idr[res->func->res_type];
! 177:
! 178: BUG_ON(res->id != -1);
! 179:
! 180: do {
! 181: if (unlikely(idr_pre_get(idr, GFP_KERNEL) == 0))
! 182: return -ENOMEM;
! 183:
! 184: write_lock(&dev_priv->resource_lock);
! 185: ret = idr_get_new_above(idr, res, 1, &res->id);
! 186: write_unlock(&dev_priv->resource_lock);
! 187:
! 188: } while (ret == -EAGAIN);
! 189:
! 190: return ret;
! 191: }
! 192:
! 193: /**
! 194: * vmw_resource_init - initialize a struct vmw_resource
! 195: *
! 196: * @dev_priv: Pointer to a device private struct.
! 197: * @res: The struct vmw_resource to initialize.
! 198: * @obj_type: Resource object type.
! 199: * @delay_id: Boolean whether to defer device id allocation until
! 200: * the first validation.
! 201: * @res_free: Resource destructor.
! 202: * @func: Resource function table.
! 203: */
! 204: int vmw_resource_init(struct vmw_private *dev_priv, struct vmw_resource *res,
! 205: bool delay_id,
! 206: void (*res_free) (struct vmw_resource *res),
! 207: const struct vmw_res_func *func)
! 208: {
! 209: kref_init(&res->kref);
! 210: res->hw_destroy = NULL;
! 211: res->res_free = res_free;
! 212: res->avail = false;
! 213: res->dev_priv = dev_priv;
! 214: res->func = func;
! 215: INIT_LIST_HEAD(&res->lru_head);
! 216: INIT_LIST_HEAD(&res->mob_head);
! 217: res->id = -1;
! 218: res->backup = NULL;
! 219: res->backup_offset = 0;
! 220: res->backup_dirty = false;
! 221: res->res_dirty = false;
! 222: if (delay_id)
! 223: return 0;
! 224: else
! 225: return vmw_resource_alloc_id(res);
! 226: }
! 227:
! 228: /**
! 229: * vmw_resource_activate
! 230: *
! 231: * @res: Pointer to the newly created resource
! 232: * @hw_destroy: Destroy function. NULL if none.
! 233: *
! 234: * Activate a resource after the hardware has been made aware of it.
! 235: * Set tye destroy function to @destroy. Typically this frees the
! 236: * resource and destroys the hardware resources associated with it.
! 237: * Activate basically means that the function vmw_resource_lookup will
! 238: * find it.
! 239: */
! 240: void vmw_resource_activate(struct vmw_resource *res,
! 241: void (*hw_destroy) (struct vmw_resource *))
! 242: {
! 243: struct vmw_private *dev_priv = res->dev_priv;
! 244:
! 245: write_lock(&dev_priv->resource_lock);
! 246: res->avail = true;
! 247: res->hw_destroy = hw_destroy;
! 248: write_unlock(&dev_priv->resource_lock);
! 249: }
! 250:
! 251: struct vmw_resource *vmw_resource_lookup(struct vmw_private *dev_priv,
! 252: struct idr *idr, int id)
! 253: {
! 254: struct vmw_resource *res;
! 255:
! 256: read_lock(&dev_priv->resource_lock);
! 257: res = idr_find(idr, id);
! 258: if (res && res->avail)
! 259: kref_get(&res->kref);
! 260: else
! 261: res = NULL;
! 262: read_unlock(&dev_priv->resource_lock);
! 263:
! 264: if (unlikely(res == NULL))
! 265: return NULL;
! 266:
! 267: return res;
! 268: }
! 269:
! 270: /**
! 271: * vmw_user_resource_lookup_handle - lookup a struct resource from a
! 272: * TTM user-space handle and perform basic type checks
! 273: *
! 274: * @dev_priv: Pointer to a device private struct
! 275: * @tfile: Pointer to a struct ttm_object_file identifying the caller
! 276: * @handle: The TTM user-space handle
! 277: * @converter: Pointer to an object describing the resource type
! 278: * @p_res: On successful return the location pointed to will contain
! 279: * a pointer to a refcounted struct vmw_resource.
! 280: *
! 281: * If the handle can't be found or is associated with an incorrect resource
! 282: * type, -EINVAL will be returned.
! 283: */
! 284: int vmw_user_resource_lookup_handle(struct vmw_private *dev_priv,
! 285: struct ttm_object_file *tfile,
! 286: uint32_t handle,
! 287: const struct vmw_user_resource_conv
! 288: *converter,
! 289: struct vmw_resource **p_res)
! 290: {
! 291: struct ttm_base_object *base;
! 292: struct vmw_resource *res;
! 293: int ret = -EINVAL;
! 294:
! 295: base = ttm_base_object_lookup(tfile, handle);
! 296: if (unlikely(base == NULL))
! 297: return -EINVAL;
! 298:
! 299: if (unlikely(base->object_type != converter->object_type))
! 300: goto out_bad_resource;
! 301:
! 302: res = converter->base_obj_to_res(base);
! 303:
! 304: read_lock(&dev_priv->resource_lock);
! 305: if (!res->avail || res->res_free != converter->res_free) {
! 306: read_unlock(&dev_priv->resource_lock);
! 307: goto out_bad_resource;
! 308: }
! 309:
! 310: kref_get(&res->kref);
! 311: read_unlock(&dev_priv->resource_lock);
! 312:
! 313: *p_res = res;
! 314: ret = 0;
! 315:
! 316: out_bad_resource:
! 317: ttm_base_object_unref(&base);
! 318:
! 319: return ret;
! 320: }
! 321:
! 322: /**
! 323: * Helper function that looks either a surface or dmabuf.
! 324: *
! 325: * The pointer this pointed at by out_surf and out_buf needs to be null.
! 326: */
! 327: int vmw_user_lookup_handle(struct vmw_private *dev_priv,
! 328: struct ttm_object_file *tfile,
! 329: uint32_t handle,
! 330: struct vmw_surface **out_surf,
! 331: struct vmw_dma_buffer **out_buf)
! 332: {
! 333: struct vmw_resource *res;
! 334: int ret;
! 335:
! 336: BUG_ON(*out_surf || *out_buf);
! 337:
! 338: ret = vmw_user_resource_lookup_handle(dev_priv, tfile, handle,
! 339: user_surface_converter,
! 340: &res);
! 341: if (!ret) {
! 342: *out_surf = vmw_res_to_srf(res);
! 343: return 0;
! 344: }
! 345:
! 346: *out_surf = NULL;
! 347: ret = vmw_user_dmabuf_lookup(tfile, handle, out_buf);
! 348: return ret;
! 349: }
! 350:
! 351: /**
! 352: * Buffer management.
! 353: */
! 354: void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo)
! 355: {
! 356: struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo);
! 357:
! 358: kfree(vmw_bo);
! 359: }
! 360:
! 361: int vmw_dmabuf_init(struct vmw_private *dev_priv,
! 362: struct vmw_dma_buffer *vmw_bo,
! 363: size_t size, struct ttm_placement *placement,
! 364: bool interruptible,
! 365: void (*bo_free) (struct ttm_buffer_object *bo))
! 366: {
! 367: struct ttm_bo_device *bdev = &dev_priv->bdev;
! 368: size_t acc_size;
! 369: int ret;
! 370:
! 371: BUG_ON(!bo_free);
! 372:
! 373: acc_size = ttm_bo_acc_size(bdev, size, sizeof(struct vmw_dma_buffer));
! 374: memset(vmw_bo, 0, sizeof(*vmw_bo));
! 375:
! 376: INIT_LIST_HEAD(&vmw_bo->res_list);
! 377:
! 378: ret = ttm_bo_init(bdev, &vmw_bo->base, size,
! 379: ttm_bo_type_device, placement,
! 380: 0, interruptible,
! 381: NULL, acc_size, NULL, bo_free);
! 382: return ret;
! 383: }
! 384:
! 385: static void vmw_user_dmabuf_destroy(struct ttm_buffer_object *bo)
! 386: {
! 387: struct vmw_user_dma_buffer *vmw_user_bo = vmw_user_dma_buffer(bo);
! 388:
! 389: ttm_base_object_kfree(vmw_user_bo, base);
! 390: }
! 391:
! 392: static void vmw_user_dmabuf_release(struct ttm_base_object **p_base)
! 393: {
! 394: struct vmw_user_dma_buffer *vmw_user_bo;
! 395: struct ttm_base_object *base = *p_base;
! 396: struct ttm_buffer_object *bo;
! 397:
! 398: *p_base = NULL;
! 399:
! 400: if (unlikely(base == NULL))
! 401: return;
! 402:
! 403: vmw_user_bo = container_of(base, struct vmw_user_dma_buffer, base);
! 404: bo = &vmw_user_bo->dma.base;
! 405: ttm_bo_unref(&bo);
! 406: }
! 407:
! 408: /**
! 409: * vmw_user_dmabuf_alloc - Allocate a user dma buffer
! 410: *
! 411: * @dev_priv: Pointer to a struct device private.
! 412: * @tfile: Pointer to a struct ttm_object_file on which to register the user
! 413: * object.
! 414: * @size: Size of the dma buffer.
! 415: * @shareable: Boolean whether the buffer is shareable with other open files.
! 416: * @handle: Pointer to where the handle value should be assigned.
! 417: * @p_dma_buf: Pointer to where the refcounted struct vmw_dma_buffer pointer
! 418: * should be assigned.
! 419: */
! 420: int vmw_user_dmabuf_alloc(struct vmw_private *dev_priv,
! 421: struct ttm_object_file *tfile,
! 422: uint32_t size,
! 423: bool shareable,
! 424: uint32_t *handle,
! 425: struct vmw_dma_buffer **p_dma_buf)
! 426: {
! 427: struct vmw_user_dma_buffer *user_bo;
! 428: struct ttm_buffer_object *tmp;
! 429: int ret;
! 430:
! 431: user_bo = kzalloc(sizeof(*user_bo), GFP_KERNEL);
! 432: if (unlikely(user_bo == NULL)) {
! 433: DRM_ERROR("Failed to allocate a buffer.\n");
! 434: return -ENOMEM;
! 435: }
! 436:
! 437: ret = vmw_dmabuf_init(dev_priv, &user_bo->dma, size,
! 438: &vmw_vram_sys_placement, true,
! 439: &vmw_user_dmabuf_destroy);
! 440: if (unlikely(ret != 0))
! 441: return ret;
! 442:
! 443: tmp = ttm_bo_reference(&user_bo->dma.base);
! 444: ret = ttm_base_object_init(tfile,
! 445: &user_bo->base,
! 446: shareable,
! 447: ttm_buffer_type,
! 448: &vmw_user_dmabuf_release, NULL);
! 449: if (unlikely(ret != 0)) {
! 450: ttm_bo_unref(&tmp);
! 451: goto out_no_base_object;
! 452: }
! 453:
! 454: *p_dma_buf = &user_bo->dma;
! 455: *handle = user_bo->base.hash.key;
! 456:
! 457: out_no_base_object:
! 458: return ret;
! 459: }
! 460:
! 461: /**
! 462: * vmw_user_dmabuf_verify_access - verify access permissions on this
! 463: * buffer object.
! 464: *
! 465: * @bo: Pointer to the buffer object being accessed
! 466: * @tfile: Identifying the caller.
! 467: */
! 468: int vmw_user_dmabuf_verify_access(struct ttm_buffer_object *bo,
! 469: struct ttm_object_file *tfile)
! 470: {
! 471: struct vmw_user_dma_buffer *vmw_user_bo;
! 472:
! 473: if (unlikely(bo->destroy != vmw_user_dmabuf_destroy))
! 474: return -EPERM;
! 475:
! 476: vmw_user_bo = vmw_user_dma_buffer(bo);
! 477: return (vmw_user_bo->base.tfile == tfile ||
! 478: vmw_user_bo->base.shareable) ? 0 : -EPERM;
! 479: }
! 480:
! 481: int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data,
! 482: struct drm_file *file_priv)
! 483: {
! 484: struct vmw_private *dev_priv = vmw_priv(dev);
! 485: union drm_vmw_alloc_dmabuf_arg *arg =
! 486: (union drm_vmw_alloc_dmabuf_arg *)data;
! 487: struct drm_vmw_alloc_dmabuf_req *req = &arg->req;
! 488: struct drm_vmw_dmabuf_rep *rep = &arg->rep;
! 489: struct vmw_dma_buffer *dma_buf;
! 490: uint32_t handle;
! 491: struct vmw_master *vmaster = vmw_master(file_priv->master);
! 492: int ret;
! 493:
! 494: ret = ttm_read_lock(&vmaster->lock, true);
! 495: if (unlikely(ret != 0))
! 496: return ret;
! 497:
! 498: ret = vmw_user_dmabuf_alloc(dev_priv, vmw_fpriv(file_priv)->tfile,
! 499: req->size, false, &handle, &dma_buf);
! 500: if (unlikely(ret != 0))
! 501: goto out_no_dmabuf;
! 502:
! 503: rep->handle = handle;
! 504: rep->map_handle = dma_buf->base.addr_space_offset;
! 505: rep->cur_gmr_id = handle;
! 506: rep->cur_gmr_offset = 0;
! 507:
! 508: vmw_dmabuf_unreference(&dma_buf);
! 509:
! 510: out_no_dmabuf:
! 511: ttm_read_unlock(&vmaster->lock);
! 512:
! 513: return ret;
! 514: }
! 515:
! 516: int vmw_dmabuf_unref_ioctl(struct drm_device *dev, void *data,
! 517: struct drm_file *file_priv)
! 518: {
! 519: struct drm_vmw_unref_dmabuf_arg *arg =
! 520: (struct drm_vmw_unref_dmabuf_arg *)data;
! 521:
! 522: return ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile,
! 523: arg->handle,
! 524: TTM_REF_USAGE);
! 525: }
! 526:
! 527: int vmw_user_dmabuf_lookup(struct ttm_object_file *tfile,
! 528: uint32_t handle, struct vmw_dma_buffer **out)
! 529: {
! 530: struct vmw_user_dma_buffer *vmw_user_bo;
! 531: struct ttm_base_object *base;
! 532:
! 533: base = ttm_base_object_lookup(tfile, handle);
! 534: if (unlikely(base == NULL)) {
! 535: printk(KERN_ERR "Invalid buffer object handle 0x%08lx.\n",
! 536: (unsigned long)handle);
! 537: return -ESRCH;
! 538: }
! 539:
! 540: if (unlikely(base->object_type != ttm_buffer_type)) {
! 541: ttm_base_object_unref(&base);
! 542: printk(KERN_ERR "Invalid buffer object handle 0x%08lx.\n",
! 543: (unsigned long)handle);
! 544: return -EINVAL;
! 545: }
! 546:
! 547: vmw_user_bo = container_of(base, struct vmw_user_dma_buffer, base);
! 548: (void)ttm_bo_reference(&vmw_user_bo->dma.base);
! 549: ttm_base_object_unref(&base);
! 550: *out = &vmw_user_bo->dma;
! 551:
! 552: return 0;
! 553: }
! 554:
! 555: int vmw_user_dmabuf_reference(struct ttm_object_file *tfile,
! 556: struct vmw_dma_buffer *dma_buf)
! 557: {
! 558: struct vmw_user_dma_buffer *user_bo;
! 559:
! 560: if (dma_buf->base.destroy != vmw_user_dmabuf_destroy)
! 561: return -EINVAL;
! 562:
! 563: user_bo = container_of(dma_buf, struct vmw_user_dma_buffer, dma);
! 564: return ttm_ref_object_add(tfile, &user_bo->base, TTM_REF_USAGE, NULL);
! 565: }
! 566:
! 567: /*
! 568: * Stream management
! 569: */
! 570:
! 571: static void vmw_stream_destroy(struct vmw_resource *res)
! 572: {
! 573: struct vmw_private *dev_priv = res->dev_priv;
! 574: struct vmw_stream *stream;
! 575: int ret;
! 576:
! 577: DRM_INFO("%s: unref\n", __func__);
! 578: stream = container_of(res, struct vmw_stream, res);
! 579:
! 580: ret = vmw_overlay_unref(dev_priv, stream->stream_id);
! 581: WARN_ON(ret != 0);
! 582: }
! 583:
! 584: static int vmw_stream_init(struct vmw_private *dev_priv,
! 585: struct vmw_stream *stream,
! 586: void (*res_free) (struct vmw_resource *res))
! 587: {
! 588: struct vmw_resource *res = &stream->res;
! 589: int ret;
! 590:
! 591: ret = vmw_resource_init(dev_priv, res, false, res_free,
! 592: &vmw_stream_func);
! 593:
! 594: if (unlikely(ret != 0)) {
! 595: if (res_free == NULL)
! 596: kfree(stream);
! 597: else
! 598: res_free(&stream->res);
! 599: return ret;
! 600: }
! 601:
! 602: ret = vmw_overlay_claim(dev_priv, &stream->stream_id);
! 603: if (ret) {
! 604: vmw_resource_unreference(&res);
! 605: return ret;
! 606: }
! 607:
! 608: DRM_INFO("%s: claimed\n", __func__);
! 609:
! 610: vmw_resource_activate(&stream->res, vmw_stream_destroy);
! 611: return 0;
! 612: }
! 613:
! 614: static void vmw_user_stream_free(struct vmw_resource *res)
! 615: {
! 616: struct vmw_user_stream *stream =
! 617: container_of(res, struct vmw_user_stream, stream.res);
! 618: struct vmw_private *dev_priv = res->dev_priv;
! 619:
! 620: ttm_base_object_kfree(stream, base);
! 621: ttm_mem_global_free(vmw_mem_glob(dev_priv),
! 622: vmw_user_stream_size);
! 623: }
! 624:
! 625: /**
! 626: * This function is called when user space has no more references on the
! 627: * base object. It releases the base-object's reference on the resource object.
! 628: */
! 629:
! 630: static void vmw_user_stream_base_release(struct ttm_base_object **p_base)
! 631: {
! 632: struct ttm_base_object *base = *p_base;
! 633: struct vmw_user_stream *stream =
! 634: container_of(base, struct vmw_user_stream, base);
! 635: struct vmw_resource *res = &stream->stream.res;
! 636:
! 637: *p_base = NULL;
! 638: vmw_resource_unreference(&res);
! 639: }
! 640:
! 641: int vmw_stream_unref_ioctl(struct drm_device *dev, void *data,
! 642: struct drm_file *file_priv)
! 643: {
! 644: struct vmw_private *dev_priv = vmw_priv(dev);
! 645: struct vmw_resource *res;
! 646: struct vmw_user_stream *stream;
! 647: struct drm_vmw_stream_arg *arg = (struct drm_vmw_stream_arg *)data;
! 648: struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
! 649: struct idr *idr = &dev_priv->res_idr[vmw_res_stream];
! 650: int ret = 0;
! 651:
! 652:
! 653: res = vmw_resource_lookup(dev_priv, idr, arg->stream_id);
! 654: if (unlikely(res == NULL))
! 655: return -EINVAL;
! 656:
! 657: if (res->res_free != &vmw_user_stream_free) {
! 658: ret = -EINVAL;
! 659: goto out;
! 660: }
! 661:
! 662: stream = container_of(res, struct vmw_user_stream, stream.res);
! 663: if (stream->base.tfile != tfile) {
! 664: ret = -EINVAL;
! 665: goto out;
! 666: }
! 667:
! 668: ttm_ref_object_base_unref(tfile, stream->base.hash.key, TTM_REF_USAGE);
! 669: out:
! 670: vmw_resource_unreference(&res);
! 671: return ret;
! 672: }
! 673:
! 674: int vmw_stream_claim_ioctl(struct drm_device *dev, void *data,
! 675: struct drm_file *file_priv)
! 676: {
! 677: struct vmw_private *dev_priv = vmw_priv(dev);
! 678: struct vmw_user_stream *stream;
! 679: struct vmw_resource *res;
! 680: struct vmw_resource *tmp;
! 681: struct drm_vmw_stream_arg *arg = (struct drm_vmw_stream_arg *)data;
! 682: struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
! 683: struct vmw_master *vmaster = vmw_master(file_priv->master);
! 684: int ret;
! 685:
! 686: /*
! 687: * Approximate idr memory usage with 128 bytes. It will be limited
! 688: * by maximum number_of streams anyway?
! 689: */
! 690:
! 691: if (unlikely(vmw_user_stream_size == 0))
! 692: vmw_user_stream_size = ttm_round_pot(sizeof(*stream)) + 128;
! 693:
! 694: ret = ttm_read_lock(&vmaster->lock, true);
! 695: if (unlikely(ret != 0))
! 696: return ret;
! 697:
! 698: ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv),
! 699: vmw_user_stream_size,
! 700: false, true);
! 701: if (unlikely(ret != 0)) {
! 702: if (ret != -ERESTARTSYS)
! 703: DRM_ERROR("Out of graphics memory for stream"
! 704: " creation.\n");
! 705: goto out_unlock;
! 706: }
! 707:
! 708:
! 709: stream = kmalloc(sizeof(*stream), GFP_KERNEL);
! 710: if (unlikely(stream == NULL)) {
! 711: ttm_mem_global_free(vmw_mem_glob(dev_priv),
! 712: vmw_user_stream_size);
! 713: ret = -ENOMEM;
! 714: goto out_unlock;
! 715: }
! 716:
! 717: res = &stream->stream.res;
! 718: stream->base.shareable = false;
! 719: stream->base.tfile = NULL;
! 720:
! 721: /*
! 722: * From here on, the destructor takes over resource freeing.
! 723: */
! 724:
! 725: ret = vmw_stream_init(dev_priv, &stream->stream, vmw_user_stream_free);
! 726: if (unlikely(ret != 0))
! 727: goto out_unlock;
! 728:
! 729: tmp = vmw_resource_reference(res);
! 730: ret = ttm_base_object_init(tfile, &stream->base, false, VMW_RES_STREAM,
! 731: &vmw_user_stream_base_release, NULL);
! 732:
! 733: if (unlikely(ret != 0)) {
! 734: vmw_resource_unreference(&tmp);
! 735: goto out_err;
! 736: }
! 737:
! 738: arg->stream_id = res->id;
! 739: out_err:
! 740: vmw_resource_unreference(&res);
! 741: out_unlock:
! 742: ttm_read_unlock(&vmaster->lock);
! 743: return ret;
! 744: }
! 745:
! 746: int vmw_user_stream_lookup(struct vmw_private *dev_priv,
! 747: struct ttm_object_file *tfile,
! 748: uint32_t *inout_id, struct vmw_resource **out)
! 749: {
! 750: struct vmw_user_stream *stream;
! 751: struct vmw_resource *res;
! 752: int ret;
! 753:
! 754: res = vmw_resource_lookup(dev_priv, &dev_priv->res_idr[vmw_res_stream],
! 755: *inout_id);
! 756: if (unlikely(res == NULL))
! 757: return -EINVAL;
! 758:
! 759: if (res->res_free != &vmw_user_stream_free) {
! 760: ret = -EINVAL;
! 761: goto err_ref;
! 762: }
! 763:
! 764: stream = container_of(res, struct vmw_user_stream, stream.res);
! 765: if (stream->base.tfile != tfile) {
! 766: ret = -EPERM;
! 767: goto err_ref;
! 768: }
! 769:
! 770: *inout_id = stream->stream.stream_id;
! 771: *out = res;
! 772: return 0;
! 773: err_ref:
! 774: vmw_resource_unreference(&res);
! 775: return ret;
! 776: }
! 777:
! 778:
! 779: int vmw_dumb_create(struct drm_file *file_priv,
! 780: struct drm_device *dev,
! 781: struct drm_mode_create_dumb *args)
! 782: {
! 783: struct vmw_private *dev_priv = vmw_priv(dev);
! 784: struct vmw_master *vmaster = vmw_master(file_priv->master);
! 785: struct vmw_user_dma_buffer *vmw_user_bo;
! 786: struct ttm_buffer_object *tmp;
! 787: int ret;
! 788:
! 789: args->pitch = args->width * ((args->bpp + 7) / 8);
! 790: args->size = args->pitch * args->height;
! 791:
! 792: vmw_user_bo = kzalloc(sizeof(*vmw_user_bo), GFP_KERNEL);
! 793: if (vmw_user_bo == NULL)
! 794: return -ENOMEM;
! 795:
! 796: ret = ttm_read_lock(&vmaster->lock, true);
! 797: if (ret != 0) {
! 798: kfree(vmw_user_bo);
! 799: return ret;
! 800: }
! 801:
! 802: ret = vmw_dmabuf_init(dev_priv, &vmw_user_bo->dma, args->size,
! 803: &vmw_vram_sys_placement, true,
! 804: &vmw_user_dmabuf_destroy);
! 805: if (ret != 0)
! 806: goto out_no_dmabuf;
! 807:
! 808: tmp = ttm_bo_reference(&vmw_user_bo->dma.base);
! 809: ret = ttm_base_object_init(vmw_fpriv(file_priv)->tfile,
! 810: &vmw_user_bo->base,
! 811: false,
! 812: ttm_buffer_type,
! 813: &vmw_user_dmabuf_release, NULL);
! 814: if (unlikely(ret != 0))
! 815: goto out_no_base_object;
! 816:
! 817: args->handle = vmw_user_bo->base.hash.key;
! 818:
! 819: out_no_base_object:
! 820: ttm_bo_unref(&tmp);
! 821: out_no_dmabuf:
! 822: ttm_read_unlock(&vmaster->lock);
! 823: return ret;
! 824: }
! 825:
! 826: int vmw_dumb_map_offset(struct drm_file *file_priv,
! 827: struct drm_device *dev, uint32_t handle,
! 828: uint64_t *offset)
! 829: {
! 830: struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
! 831: struct vmw_dma_buffer *out_buf;
! 832: int ret;
! 833:
! 834: ret = vmw_user_dmabuf_lookup(tfile, handle, &out_buf);
! 835: if (ret != 0)
! 836: return -EINVAL;
! 837:
! 838: *offset = out_buf->base.addr_space_offset;
! 839: vmw_dmabuf_unreference(&out_buf);
! 840: return 0;
! 841: }
! 842:
! 843: int vmw_dumb_destroy(struct drm_file *file_priv,
! 844: struct drm_device *dev,
! 845: uint32_t handle)
! 846: {
! 847: return ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile,
! 848: handle, TTM_REF_USAGE);
! 849: }
! 850:
! 851: /**
! 852: * vmw_resource_buf_alloc - Allocate a backup buffer for a resource.
! 853: *
! 854: * @res: The resource for which to allocate a backup buffer.
! 855: * @interruptible: Whether any sleeps during allocation should be
! 856: * performed while interruptible.
! 857: */
! 858: static int vmw_resource_buf_alloc(struct vmw_resource *res,
! 859: bool interruptible)
! 860: {
! 861: unsigned long size =
! 862: (res->backup_size + PAGE_SIZE - 1) & PAGE_MASK;
! 863: struct vmw_dma_buffer *backup;
! 864: int ret;
! 865:
! 866: if (likely(res->backup)) {
! 867: BUG_ON(res->backup->base.num_pages * PAGE_SIZE < size);
! 868: return 0;
! 869: }
! 870:
! 871: backup = kzalloc(sizeof(*backup), GFP_KERNEL);
! 872: if (unlikely(backup == NULL))
! 873: return -ENOMEM;
! 874:
! 875: ret = vmw_dmabuf_init(res->dev_priv, backup, res->backup_size,
! 876: res->func->backup_placement,
! 877: interruptible,
! 878: &vmw_dmabuf_bo_free);
! 879: if (unlikely(ret != 0))
! 880: goto out_no_dmabuf;
! 881:
! 882: res->backup = backup;
! 883:
! 884: out_no_dmabuf:
! 885: return ret;
! 886: }
! 887:
! 888: /**
! 889: * vmw_resource_do_validate - Make a resource up-to-date and visible
! 890: * to the device.
! 891: *
! 892: * @res: The resource to make visible to the device.
! 893: * @val_buf: Information about a buffer possibly
! 894: * containing backup data if a bind operation is needed.
! 895: *
! 896: * On hardware resource shortage, this function returns -EBUSY and
! 897: * should be retried once resources have been freed up.
! 898: */
! 899: static int vmw_resource_do_validate(struct vmw_resource *res,
! 900: struct ttm_validate_buffer *val_buf)
! 901: {
! 902: int ret = 0;
! 903: const struct vmw_res_func *func = res->func;
! 904:
! 905: if (unlikely(res->id == -1)) {
! 906: ret = func->create(res);
! 907: if (unlikely(ret != 0))
! 908: return ret;
! 909: }
! 910:
! 911: if (func->bind &&
! 912: ((func->needs_backup && list_empty(&res->mob_head) &&
! 913: val_buf->bo != NULL) ||
! 914: (!func->needs_backup && val_buf->bo != NULL))) {
! 915: ret = func->bind(res, val_buf);
! 916: if (unlikely(ret != 0))
! 917: goto out_bind_failed;
! 918: if (func->needs_backup)
! 919: list_add_tail(&res->mob_head, &res->backup->res_list);
! 920: }
! 921:
! 922: /*
! 923: * Only do this on write operations, and move to
! 924: * vmw_resource_unreserve if it can be called after
! 925: * backup buffers have been unreserved. Otherwise
! 926: * sort out locking.
! 927: */
! 928: res->res_dirty = true;
! 929:
! 930: return 0;
! 931:
! 932: out_bind_failed:
! 933: func->destroy(res);
! 934:
! 935: return ret;
! 936: }
! 937:
! 938: /**
! 939: * vmw_resource_unreserve - Unreserve a resource previously reserved for
! 940: * command submission.
! 941: *
! 942: * @res: Pointer to the struct vmw_resource to unreserve.
! 943: * @new_backup: Pointer to new backup buffer if command submission
! 944: * switched.
! 945: * @new_backup_offset: New backup offset if @new_backup is !NULL.
! 946: *
! 947: * Currently unreserving a resource means putting it back on the device's
! 948: * resource lru list, so that it can be evicted if necessary.
! 949: */
! 950: void vmw_resource_unreserve(struct vmw_resource *res,
! 951: struct vmw_dma_buffer *new_backup,
! 952: unsigned long new_backup_offset)
! 953: {
! 954: struct vmw_private *dev_priv = res->dev_priv;
! 955:
! 956: if (!list_empty(&res->lru_head))
! 957: return;
! 958:
! 959: if (new_backup && new_backup != res->backup) {
! 960:
! 961: if (res->backup) {
! 962: BUG_ON(atomic_read(&res->backup->base.reserved) == 0);
! 963: list_del_init(&res->mob_head);
! 964: vmw_dmabuf_unreference(&res->backup);
! 965: }
! 966:
! 967: res->backup = vmw_dmabuf_reference(new_backup);
! 968: BUG_ON(atomic_read(&new_backup->base.reserved) == 0);
! 969: list_add_tail(&res->mob_head, &new_backup->res_list);
! 970: }
! 971: if (new_backup)
! 972: res->backup_offset = new_backup_offset;
! 973:
! 974: if (!res->func->may_evict)
! 975: return;
! 976:
! 977: write_lock(&dev_priv->resource_lock);
! 978: list_add_tail(&res->lru_head,
! 979: &res->dev_priv->res_lru[res->func->res_type]);
! 980: write_unlock(&dev_priv->resource_lock);
! 981: }
! 982:
! 983: /**
! 984: * vmw_resource_check_buffer - Check whether a backup buffer is needed
! 985: * for a resource and in that case, allocate
! 986: * one, reserve and validate it.
! 987: *
! 988: * @res: The resource for which to allocate a backup buffer.
! 989: * @interruptible: Whether any sleeps during allocation should be
! 990: * performed while interruptible.
! 991: * @val_buf: On successful return contains data about the
! 992: * reserved and validated backup buffer.
! 993: */
! 994: int vmw_resource_check_buffer(struct vmw_resource *res,
! 995: bool interruptible,
! 996: struct ttm_validate_buffer *val_buf)
! 997: {
! 998: struct list_head val_list;
! 999: bool backup_dirty = false;
! 1000: int ret;
! 1001:
! 1002: if (unlikely(res->backup == NULL)) {
! 1003: ret = vmw_resource_buf_alloc(res, interruptible);
! 1004: if (unlikely(ret != 0))
! 1005: return ret;
! 1006: }
! 1007:
! 1008: INIT_LIST_HEAD(&val_list);
! 1009: val_buf->bo = ttm_bo_reference(&res->backup->base);
! 1010: list_add_tail(&val_buf->head, &val_list);
! 1011: ret = ttm_eu_reserve_buffers(&val_list);
! 1012: if (unlikely(ret != 0))
! 1013: goto out_no_reserve;
! 1014:
! 1015: if (res->func->needs_backup && list_empty(&res->mob_head))
! 1016: return 0;
! 1017:
! 1018: backup_dirty = res->backup_dirty;
! 1019: ret = ttm_bo_validate(&res->backup->base,
! 1020: res->func->backup_placement,
! 1021: true, false);
! 1022:
! 1023: if (unlikely(ret != 0))
! 1024: goto out_no_validate;
! 1025:
! 1026: return 0;
! 1027:
! 1028: out_no_validate:
! 1029: ttm_eu_backoff_reservation(&val_list);
! 1030: out_no_reserve:
! 1031: ttm_bo_unref(&val_buf->bo);
! 1032: if (backup_dirty)
! 1033: vmw_dmabuf_unreference(&res->backup);
! 1034:
! 1035: return ret;
! 1036: }
! 1037:
! 1038: /**
! 1039: * vmw_resource_reserve - Reserve a resource for command submission
! 1040: *
! 1041: * @res: The resource to reserve.
! 1042: *
! 1043: * This function takes the resource off the LRU list and make sure
! 1044: * a backup buffer is present for guest-backed resources. However,
! 1045: * the buffer may not be bound to the resource at this point.
! 1046: *
! 1047: */
! 1048: int vmw_resource_reserve(struct vmw_resource *res, bool no_backup)
! 1049: {
! 1050: struct vmw_private *dev_priv = res->dev_priv;
! 1051: int ret;
! 1052:
! 1053: write_lock(&dev_priv->resource_lock);
! 1054: list_del_init(&res->lru_head);
! 1055: write_unlock(&dev_priv->resource_lock);
! 1056:
! 1057: if (res->func->needs_backup && res->backup == NULL &&
! 1058: !no_backup) {
! 1059: ret = vmw_resource_buf_alloc(res, true);
! 1060: if (unlikely(ret != 0))
! 1061: return ret;
! 1062: }
! 1063:
! 1064: return 0;
! 1065: }
! 1066:
! 1067: /**
! 1068: * vmw_resource_backoff_reservation - Unreserve and unreference a
! 1069: * backup buffer
! 1070: *.
! 1071: * @val_buf: Backup buffer information.
! 1072: */
! 1073: void vmw_resource_backoff_reservation(struct ttm_validate_buffer *val_buf)
! 1074: {
! 1075: struct list_head val_list;
! 1076:
! 1077: if (likely(val_buf->bo == NULL))
! 1078: return;
! 1079:
! 1080: INIT_LIST_HEAD(&val_list);
! 1081: list_add_tail(&val_buf->head, &val_list);
! 1082: ttm_eu_backoff_reservation(&val_list);
! 1083: ttm_bo_unref(&val_buf->bo);
! 1084: }
! 1085:
! 1086: /**
! 1087: * vmw_resource_do_evict - Evict a resource, and transfer its data
! 1088: * to a backup buffer.
! 1089: *
! 1090: * @res: The resource to evict.
! 1091: */
! 1092: int vmw_resource_do_evict(struct vmw_resource *res)
! 1093: {
! 1094: struct ttm_validate_buffer val_buf;
! 1095: const struct vmw_res_func *func = res->func;
! 1096: int ret;
! 1097:
! 1098: BUG_ON(!func->may_evict);
! 1099:
! 1100: val_buf.bo = NULL;
! 1101: ret = vmw_resource_check_buffer(res, true, &val_buf);
! 1102: if (unlikely(ret != 0))
! 1103: return ret;
! 1104:
! 1105: if (unlikely(func->unbind != NULL &&
! 1106: (!func->needs_backup || !list_empty(&res->mob_head)))) {
! 1107: ret = func->unbind(res, res->res_dirty, &val_buf);
! 1108: if (unlikely(ret != 0))
! 1109: goto out_no_unbind;
! 1110: list_del_init(&res->mob_head);
! 1111: }
! 1112: ret = func->destroy(res);
! 1113: res->backup_dirty = true;
! 1114: res->res_dirty = false;
! 1115: out_no_unbind:
! 1116: vmw_resource_backoff_reservation(&val_buf);
! 1117:
! 1118: return ret;
! 1119: }
! 1120:
! 1121:
! 1122: /**
! 1123: * vmw_resource_validate - Make a resource up-to-date and visible
! 1124: * to the device.
! 1125: *
! 1126: * @res: The resource to make visible to the device.
! 1127: *
! 1128: * On succesful return, any backup DMA buffer pointed to by @res->backup will
! 1129: * be reserved and validated.
! 1130: * On hardware resource shortage, this function will repeatedly evict
! 1131: * resources of the same type until the validation succeeds.
! 1132: */
! 1133: int vmw_resource_validate(struct vmw_resource *res)
! 1134: {
! 1135: int ret;
! 1136: struct vmw_resource *evict_res;
! 1137: struct vmw_private *dev_priv = res->dev_priv;
! 1138: struct list_head *lru_list = &dev_priv->res_lru[res->func->res_type];
! 1139: struct ttm_validate_buffer val_buf;
! 1140:
! 1141: if (likely(!res->func->may_evict))
! 1142: return 0;
! 1143:
! 1144: val_buf.bo = NULL;
! 1145: if (res->backup)
! 1146: val_buf.bo = &res->backup->base;
! 1147: do {
! 1148: ret = vmw_resource_do_validate(res, &val_buf);
! 1149: if (likely(ret != -EBUSY))
! 1150: break;
! 1151:
! 1152: write_lock(&dev_priv->resource_lock);
! 1153: if (list_empty(lru_list) || !res->func->may_evict) {
! 1154: DRM_ERROR("Out of device device id entries "
! 1155: "for %s.\n", res->func->type_name);
! 1156: ret = -EBUSY;
! 1157: write_unlock(&dev_priv->resource_lock);
! 1158: break;
! 1159: }
! 1160:
! 1161: evict_res = vmw_resource_reference
! 1162: (list_first_entry(lru_list, struct vmw_resource,
! 1163: lru_head));
! 1164: list_del_init(&evict_res->lru_head);
! 1165:
! 1166: write_unlock(&dev_priv->resource_lock);
! 1167: vmw_resource_do_evict(evict_res);
! 1168: vmw_resource_unreference(&evict_res);
! 1169: } while (1);
! 1170:
! 1171: if (unlikely(ret != 0))
! 1172: goto out_no_validate;
! 1173: else if (!res->func->needs_backup && res->backup) {
! 1174: list_del_init(&res->mob_head);
! 1175: vmw_dmabuf_unreference(&res->backup);
! 1176: }
! 1177:
! 1178: return 0;
! 1179:
! 1180: out_no_validate:
! 1181: return ret;
! 1182: }
! 1183:
! 1184: /**
! 1185: * vmw_fence_single_bo - Utility function to fence a single TTM buffer
! 1186: * object without unreserving it.
! 1187: *
! 1188: * @bo: Pointer to the struct ttm_buffer_object to fence.
! 1189: * @fence: Pointer to the fence. If NULL, this function will
! 1190: * insert a fence into the command stream..
! 1191: *
! 1192: * Contrary to the ttm_eu version of this function, it takes only
! 1193: * a single buffer object instead of a list, and it also doesn't
! 1194: * unreserve the buffer object, which needs to be done separately.
! 1195: */
! 1196: void vmw_fence_single_bo(struct ttm_buffer_object *bo,
! 1197: struct vmw_fence_obj *fence)
! 1198: {
! 1199: struct ttm_bo_device *bdev = bo->bdev;
! 1200: struct ttm_bo_driver *driver = bdev->driver;
! 1201: struct vmw_fence_obj *old_fence_obj;
! 1202: struct vmw_private *dev_priv =
! 1203: container_of(bdev, struct vmw_private, bdev);
! 1204:
! 1205: if (fence == NULL)
! 1206: vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL);
! 1207: else
! 1208: driver->sync_obj_ref(fence);
! 1209:
! 1210: spin_lock(&bdev->fence_lock);
! 1211:
! 1212: old_fence_obj = bo->sync_obj;
! 1213: bo->sync_obj = fence;
! 1214:
! 1215: spin_unlock(&bdev->fence_lock);
! 1216:
! 1217: if (old_fence_obj)
! 1218: vmw_fence_obj_unreference(&old_fence_obj);
! 1219: }
! 1220:
! 1221: /**
! 1222: * vmw_resource_move_notify - TTM move_notify_callback
! 1223: *
! 1224: * @bo: The TTM buffer object about to move.
! 1225: * @mem: The truct ttm_mem_reg indicating to what memory
! 1226: * region the move is taking place.
! 1227: *
! 1228: * For now does nothing.
! 1229: */
! 1230: void vmw_resource_move_notify(struct ttm_buffer_object *bo,
! 1231: struct ttm_mem_reg *mem)
! 1232: {
! 1233: }
! 1234:
! 1235: /**
! 1236: * vmw_resource_needs_backup - Return whether a resource needs a backup buffer.
! 1237: *
! 1238: * @res: The resource being queried.
! 1239: */
! 1240: bool vmw_resource_needs_backup(const struct vmw_resource *res)
! 1241: {
! 1242: return res->func->needs_backup;
! 1243: }
! 1244:
! 1245: /**
! 1246: * vmw_resource_evict_type - Evict all resources of a specific type
! 1247: *
! 1248: * @dev_priv: Pointer to a device private struct
! 1249: * @type: The resource type to evict
! 1250: *
! 1251: * To avoid thrashing starvation or as part of the hibernation sequence,
! 1252: * evict all evictable resources of a specific type.
! 1253: */
! 1254: static void vmw_resource_evict_type(struct vmw_private *dev_priv,
! 1255: enum vmw_res_type type)
! 1256: {
! 1257: struct list_head *lru_list = &dev_priv->res_lru[type];
! 1258: struct vmw_resource *evict_res;
! 1259:
! 1260: do {
! 1261: write_lock(&dev_priv->resource_lock);
! 1262:
! 1263: if (list_empty(lru_list))
! 1264: goto out_unlock;
! 1265:
! 1266: evict_res = vmw_resource_reference(
! 1267: list_first_entry(lru_list, struct vmw_resource,
! 1268: lru_head));
! 1269: list_del_init(&evict_res->lru_head);
! 1270: write_unlock(&dev_priv->resource_lock);
! 1271: vmw_resource_do_evict(evict_res);
! 1272: vmw_resource_unreference(&evict_res);
! 1273: } while (1);
! 1274:
! 1275: out_unlock:
! 1276: write_unlock(&dev_priv->resource_lock);
! 1277: }
! 1278:
! 1279: /**
! 1280: * vmw_resource_evict_all - Evict all evictable resources
! 1281: *
! 1282: * @dev_priv: Pointer to a device private struct
! 1283: *
! 1284: * To avoid thrashing starvation or as part of the hibernation sequence,
! 1285: * evict all evictable resources. In particular this means that all
! 1286: * guest-backed resources that are registered with the device are
! 1287: * evicted and the OTable becomes clean.
! 1288: */
! 1289: void vmw_resource_evict_all(struct vmw_private *dev_priv)
! 1290: {
! 1291: enum vmw_res_type type;
! 1292:
! 1293: mutex_lock(&dev_priv->cmdbuf_mutex);
! 1294:
! 1295: for (type = 0; type < vmw_res_max; ++type)
! 1296: vmw_resource_evict_type(dev_priv, type);
! 1297:
! 1298: mutex_unlock(&dev_priv->cmdbuf_mutex);
! 1299: }
CVSweb <webmaster@jp.NetBSD.org>