162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR MIT
262306a36Sopenharmony_ci/**************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright 2009-2011 VMware, Inc., Palo Alto, CA., USA
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
762306a36Sopenharmony_ci * copy of this software and associated documentation files (the
862306a36Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
962306a36Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
1062306a36Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
1162306a36Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
1262306a36Sopenharmony_ci * the following conditions:
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the
1562306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
1662306a36Sopenharmony_ci * of the Software.
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1962306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2062306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
2162306a36Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
2262306a36Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
2362306a36Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
2462306a36Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE.
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci **************************************************************************/
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#include "vmwgfx_drv.h"
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic int vmw_bo_vm_lookup(struct ttm_device *bdev,
3162306a36Sopenharmony_ci				   struct drm_file *filp,
3262306a36Sopenharmony_ci				   unsigned long offset,
3362306a36Sopenharmony_ci				   unsigned long pages,
3462306a36Sopenharmony_ci				   struct ttm_buffer_object **p_bo)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	struct vmw_private *dev_priv = container_of(bdev, struct vmw_private, bdev);
3762306a36Sopenharmony_ci	struct drm_device *drm = &dev_priv->drm;
3862306a36Sopenharmony_ci	struct drm_vma_offset_node *node;
3962306a36Sopenharmony_ci	int ret;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	*p_bo = NULL;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	drm_vma_offset_lock_lookup(bdev->vma_manager);
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	node = drm_vma_offset_lookup_locked(bdev->vma_manager, offset, pages);
4662306a36Sopenharmony_ci	if (likely(node)) {
4762306a36Sopenharmony_ci		*p_bo = container_of(node, struct ttm_buffer_object,
4862306a36Sopenharmony_ci				  base.vma_node);
4962306a36Sopenharmony_ci		*p_bo = ttm_bo_get_unless_zero(*p_bo);
5062306a36Sopenharmony_ci	}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	drm_vma_offset_unlock_lookup(bdev->vma_manager);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	if (!*p_bo) {
5562306a36Sopenharmony_ci		drm_err(drm, "Could not find buffer object to map\n");
5662306a36Sopenharmony_ci		return -EINVAL;
5762306a36Sopenharmony_ci	}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	if (!drm_vma_node_is_allowed(node, filp)) {
6062306a36Sopenharmony_ci		ret = -EACCES;
6162306a36Sopenharmony_ci		goto out_no_access;
6262306a36Sopenharmony_ci	}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	return 0;
6562306a36Sopenharmony_ciout_no_access:
6662306a36Sopenharmony_ci	ttm_bo_put(*p_bo);
6762306a36Sopenharmony_ci	return ret;
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ciint vmw_mmap(struct file *filp, struct vm_area_struct *vma)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	static const struct vm_operations_struct vmw_vm_ops = {
7362306a36Sopenharmony_ci		.pfn_mkwrite = vmw_bo_vm_mkwrite,
7462306a36Sopenharmony_ci		.page_mkwrite = vmw_bo_vm_mkwrite,
7562306a36Sopenharmony_ci		.fault = vmw_bo_vm_fault,
7662306a36Sopenharmony_ci		.open = ttm_bo_vm_open,
7762306a36Sopenharmony_ci		.close = ttm_bo_vm_close,
7862306a36Sopenharmony_ci	};
7962306a36Sopenharmony_ci	struct drm_file *file_priv = filp->private_data;
8062306a36Sopenharmony_ci	struct vmw_private *dev_priv = vmw_priv(file_priv->minor->dev);
8162306a36Sopenharmony_ci	struct ttm_device *bdev = &dev_priv->bdev;
8262306a36Sopenharmony_ci	struct ttm_buffer_object *bo;
8362306a36Sopenharmony_ci	int ret;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET_START))
8662306a36Sopenharmony_ci		return -EINVAL;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	ret = vmw_bo_vm_lookup(bdev, file_priv, vma->vm_pgoff, vma_pages(vma), &bo);
8962306a36Sopenharmony_ci	if (unlikely(ret != 0))
9062306a36Sopenharmony_ci		return ret;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	ret = ttm_bo_mmap_obj(vma, bo);
9362306a36Sopenharmony_ci	if (unlikely(ret != 0))
9462306a36Sopenharmony_ci		goto out_unref;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	vma->vm_ops = &vmw_vm_ops;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	/* Use VM_PFNMAP rather than VM_MIXEDMAP if not a COW mapping */
9962306a36Sopenharmony_ci	if (!is_cow_mapping(vma->vm_flags))
10062306a36Sopenharmony_ci		vm_flags_mod(vma, VM_PFNMAP, VM_MIXEDMAP);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	ttm_bo_put(bo); /* release extra ref taken by ttm_bo_mmap_obj() */
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	return 0;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ciout_unref:
10762306a36Sopenharmony_ci	ttm_bo_put(bo);
10862306a36Sopenharmony_ci	return ret;
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
111