brintos

brintos / linux-shallow public Read only

0
0
Text · 8.2 KiB · 6c2a2f2 Raw
248 lines · c
1#ifndef __DRM_VMA_MANAGER_H__2#define __DRM_VMA_MANAGER_H__3 4/*5 * Copyright (c) 2013 David Herrmann <dh.herrmann@gmail.com>6 *7 * Permission is hereby granted, free of charge, to any person obtaining a8 * copy of this software and associated documentation files (the "Software"),9 * to deal in the Software without restriction, including without limitation10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,11 * and/or sell copies of the Software, and to permit persons to whom the12 * Software is furnished to do so, subject to the following conditions:13 *14 * The above copyright notice and this permission notice shall be included in15 * all copies or substantial portions of the Software.16 *17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL20 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR23 * OTHER DEALINGS IN THE SOFTWARE.24 */25 26#include <drm/drm_mm.h>27#include <linux/mm.h>28#include <linux/rbtree.h>29#include <linux/spinlock.h>30#include <linux/types.h>31 32/* We make up offsets for buffer objects so we can recognize them at33 * mmap time. pgoff in mmap is an unsigned long, so we need to make sure34 * that the faked up offset will fit35 */36#if BITS_PER_LONG == 6437#define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFFUL >> PAGE_SHIFT) + 1)38#define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFFUL >> PAGE_SHIFT) * 256)39#else40#define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFUL >> PAGE_SHIFT) + 1)41#define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFUL >> PAGE_SHIFT) * 16)42#endif43 44struct drm_file;45 46struct drm_vma_offset_file {47	struct rb_node vm_rb;48	struct drm_file *vm_tag;49	unsigned long vm_count;50};51 52struct drm_vma_offset_node {53	rwlock_t vm_lock;54	struct drm_mm_node vm_node;55	struct rb_root vm_files;56	void *driver_private;57};58 59struct drm_vma_offset_manager {60	rwlock_t vm_lock;61	struct drm_mm vm_addr_space_mm;62};63 64void drm_vma_offset_manager_init(struct drm_vma_offset_manager *mgr,65				 unsigned long page_offset, unsigned long size);66void drm_vma_offset_manager_destroy(struct drm_vma_offset_manager *mgr);67 68struct drm_vma_offset_node *drm_vma_offset_lookup_locked(struct drm_vma_offset_manager *mgr,69							   unsigned long start,70							   unsigned long pages);71int drm_vma_offset_add(struct drm_vma_offset_manager *mgr,72		       struct drm_vma_offset_node *node, unsigned long pages);73void drm_vma_offset_remove(struct drm_vma_offset_manager *mgr,74			   struct drm_vma_offset_node *node);75 76int drm_vma_node_allow(struct drm_vma_offset_node *node, struct drm_file *tag);77int drm_vma_node_allow_once(struct drm_vma_offset_node *node, struct drm_file *tag);78void drm_vma_node_revoke(struct drm_vma_offset_node *node,79			 struct drm_file *tag);80bool drm_vma_node_is_allowed(struct drm_vma_offset_node *node,81			     struct drm_file *tag);82 83/**84 * drm_vma_offset_exact_lookup_locked() - Look up node by exact address85 * @mgr: Manager object86 * @start: Start address (page-based, not byte-based)87 * @pages: Size of object (page-based)88 *89 * Same as drm_vma_offset_lookup_locked() but does not allow any offset into the node.90 * It only returns the exact object with the given start address.91 *92 * RETURNS:93 * Node at exact start address @start.94 */95static inline struct drm_vma_offset_node *96drm_vma_offset_exact_lookup_locked(struct drm_vma_offset_manager *mgr,97				   unsigned long start,98				   unsigned long pages)99{100	struct drm_vma_offset_node *node;101 102	node = drm_vma_offset_lookup_locked(mgr, start, pages);103	return (node && node->vm_node.start == start) ? node : NULL;104}105 106/**107 * drm_vma_offset_lock_lookup() - Lock lookup for extended private use108 * @mgr: Manager object109 *110 * Lock VMA manager for extended lookups. Only locked VMA function calls111 * are allowed while holding this lock. All other contexts are blocked from VMA112 * until the lock is released via drm_vma_offset_unlock_lookup().113 *114 * Use this if you need to take a reference to the objects returned by115 * drm_vma_offset_lookup_locked() before releasing this lock again.116 *117 * This lock must not be used for anything else than extended lookups. You must118 * not call any other VMA helpers while holding this lock.119 *120 * Note: You're in atomic-context while holding this lock!121 */122static inline void drm_vma_offset_lock_lookup(struct drm_vma_offset_manager *mgr)123{124	read_lock(&mgr->vm_lock);125}126 127/**128 * drm_vma_offset_unlock_lookup() - Unlock lookup for extended private use129 * @mgr: Manager object130 *131 * Release lookup-lock. See drm_vma_offset_lock_lookup() for more information.132 */133static inline void drm_vma_offset_unlock_lookup(struct drm_vma_offset_manager *mgr)134{135	read_unlock(&mgr->vm_lock);136}137 138/**139 * drm_vma_node_reset() - Initialize or reset node object140 * @node: Node to initialize or reset141 *142 * Reset a node to its initial state. This must be called before using it with143 * any VMA offset manager.144 *145 * This must not be called on an already allocated node, or you will leak146 * memory.147 */148static inline void drm_vma_node_reset(struct drm_vma_offset_node *node)149{150	memset(node, 0, sizeof(*node));151	node->vm_files = RB_ROOT;152	rwlock_init(&node->vm_lock);153}154 155/**156 * drm_vma_node_start() - Return start address for page-based addressing157 * @node: Node to inspect158 *159 * Return the start address of the given node. This can be used as offset into160 * the linear VM space that is provided by the VMA offset manager. Note that161 * this can only be used for page-based addressing. If you need a proper offset162 * for user-space mappings, you must apply "<< PAGE_SHIFT" or use the163 * drm_vma_node_offset_addr() helper instead.164 *165 * RETURNS:166 * Start address of @node for page-based addressing. 0 if the node does not167 * have an offset allocated.168 */169static inline unsigned long drm_vma_node_start(const struct drm_vma_offset_node *node)170{171	return node->vm_node.start;172}173 174/**175 * drm_vma_node_size() - Return size (page-based)176 * @node: Node to inspect177 *178 * Return the size as number of pages for the given node. This is the same size179 * that was passed to drm_vma_offset_add(). If no offset is allocated for the180 * node, this is 0.181 *182 * RETURNS:183 * Size of @node as number of pages. 0 if the node does not have an offset184 * allocated.185 */186static inline unsigned long drm_vma_node_size(struct drm_vma_offset_node *node)187{188	return node->vm_node.size;189}190 191/**192 * drm_vma_node_offset_addr() - Return sanitized offset for user-space mmaps193 * @node: Linked offset node194 *195 * Same as drm_vma_node_start() but returns the address as a valid offset that196 * can be used for user-space mappings during mmap().197 * This must not be called on unlinked nodes.198 *199 * RETURNS:200 * Offset of @node for byte-based addressing. 0 if the node does not have an201 * object allocated.202 */203static inline __u64 drm_vma_node_offset_addr(struct drm_vma_offset_node *node)204{205	return ((__u64)node->vm_node.start) << PAGE_SHIFT;206}207 208/**209 * drm_vma_node_unmap() - Unmap offset node210 * @node: Offset node211 * @file_mapping: Address space to unmap @node from212 *213 * Unmap all userspace mappings for a given offset node. The mappings must be214 * associated with the @file_mapping address-space. If no offset exists215 * nothing is done.216 *217 * This call is unlocked. The caller must guarantee that drm_vma_offset_remove()218 * is not called on this node concurrently.219 */220static inline void drm_vma_node_unmap(struct drm_vma_offset_node *node,221				      struct address_space *file_mapping)222{223	if (drm_mm_node_allocated(&node->vm_node))224		unmap_mapping_range(file_mapping,225				    drm_vma_node_offset_addr(node),226				    drm_vma_node_size(node) << PAGE_SHIFT, 1);227}228 229/**230 * drm_vma_node_verify_access() - Access verification helper for TTM231 * @node: Offset node232 * @tag: Tag of file to check233 *234 * This checks whether @tag is granted access to @node. It is the same as235 * drm_vma_node_is_allowed() but suitable as drop-in helper for TTM236 * verify_access() callbacks.237 *238 * RETURNS:239 * 0 if access is granted, -EACCES otherwise.240 */241static inline int drm_vma_node_verify_access(struct drm_vma_offset_node *node,242					     struct drm_file *tag)243{244	return drm_vma_node_is_allowed(node, tag) ? 0 : -EACCES;245}246 247#endif /* __DRM_VMA_MANAGER_H__ */248