1 1.2 riastrad /* $NetBSD: drm_vma_manager.h,v 1.3 2021/12/18 23:45:46 riastradh Exp $ */ 2 1.2 riastrad 3 1.1 riastrad #ifndef __DRM_VMA_MANAGER_H__ 4 1.1 riastrad #define __DRM_VMA_MANAGER_H__ 5 1.1 riastrad 6 1.1 riastrad /* 7 1.1 riastrad * Copyright (c) 2013 David Herrmann <dh.herrmann (at) gmail.com> 8 1.1 riastrad * 9 1.1 riastrad * Permission is hereby granted, free of charge, to any person obtaining a 10 1.1 riastrad * copy of this software and associated documentation files (the "Software"), 11 1.1 riastrad * to deal in the Software without restriction, including without limitation 12 1.1 riastrad * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 1.1 riastrad * and/or sell copies of the Software, and to permit persons to whom the 14 1.1 riastrad * Software is furnished to do so, subject to the following conditions: 15 1.1 riastrad * 16 1.1 riastrad * The above copyright notice and this permission notice shall be included in 17 1.1 riastrad * all copies or substantial portions of the Software. 18 1.1 riastrad * 19 1.1 riastrad * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 1.1 riastrad * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 1.1 riastrad * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 1.1 riastrad * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 1.1 riastrad * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 1.1 riastrad * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 1.1 riastrad * OTHER DEALINGS IN THE SOFTWARE. 26 1.1 riastrad */ 27 1.1 riastrad 28 1.1 riastrad #include <drm/drm_mm.h> 29 1.1 riastrad #include <linux/mm.h> 30 1.1 riastrad #include <linux/rbtree.h> 31 1.1 riastrad #include <linux/spinlock.h> 32 1.1 riastrad #include <linux/types.h> 33 1.1 riastrad 34 1.3 riastrad /* We make up offsets for buffer objects so we can recognize them at 35 1.3 riastrad * mmap time. pgoff in mmap is an unsigned long, so we need to make sure 36 1.3 riastrad * that the faked up offset will fit 37 1.3 riastrad */ 38 1.3 riastrad #if BITS_PER_LONG == 64 39 1.3 riastrad #define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFFUL >> PAGE_SHIFT) + 1) 40 1.3 riastrad #define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFFUL >> PAGE_SHIFT) * 256) 41 1.3 riastrad #else 42 1.3 riastrad #define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFUL >> PAGE_SHIFT) + 1) 43 1.3 riastrad #define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFUL >> PAGE_SHIFT) * 16) 44 1.3 riastrad #endif 45 1.3 riastrad 46 1.3 riastrad struct drm_file; 47 1.3 riastrad 48 1.1 riastrad struct drm_vma_offset_file { 49 1.1 riastrad struct rb_node vm_rb; 50 1.3 riastrad struct drm_file *vm_tag; 51 1.1 riastrad unsigned long vm_count; 52 1.1 riastrad }; 53 1.1 riastrad 54 1.1 riastrad struct drm_vma_offset_node { 55 1.1 riastrad rwlock_t vm_lock; 56 1.1 riastrad struct drm_mm_node vm_node; 57 1.1 riastrad struct rb_root vm_files; 58 1.3 riastrad bool readonly:1; 59 1.1 riastrad }; 60 1.1 riastrad 61 1.1 riastrad struct drm_vma_offset_manager { 62 1.1 riastrad rwlock_t vm_lock; 63 1.1 riastrad struct drm_mm vm_addr_space_mm; 64 1.1 riastrad }; 65 1.1 riastrad 66 1.1 riastrad void drm_vma_offset_manager_init(struct drm_vma_offset_manager *mgr, 67 1.1 riastrad unsigned long page_offset, unsigned long size); 68 1.1 riastrad void drm_vma_offset_manager_destroy(struct drm_vma_offset_manager *mgr); 69 1.1 riastrad 70 1.1 riastrad struct drm_vma_offset_node *drm_vma_offset_lookup_locked(struct drm_vma_offset_manager *mgr, 71 1.1 riastrad unsigned long start, 72 1.1 riastrad unsigned long pages); 73 1.1 riastrad int drm_vma_offset_add(struct drm_vma_offset_manager *mgr, 74 1.1 riastrad struct drm_vma_offset_node *node, unsigned long pages); 75 1.1 riastrad void drm_vma_offset_remove(struct drm_vma_offset_manager *mgr, 76 1.1 riastrad struct drm_vma_offset_node *node); 77 1.1 riastrad 78 1.3 riastrad int drm_vma_node_allow(struct drm_vma_offset_node *node, struct drm_file *tag); 79 1.3 riastrad void drm_vma_node_revoke(struct drm_vma_offset_node *node, 80 1.3 riastrad struct drm_file *tag); 81 1.1 riastrad bool drm_vma_node_is_allowed(struct drm_vma_offset_node *node, 82 1.3 riastrad struct drm_file *tag); 83 1.1 riastrad 84 1.1 riastrad /** 85 1.2 riastrad * drm_vma_offset_exact_lookup_locked() - Look up node by exact address 86 1.1 riastrad * @mgr: Manager object 87 1.1 riastrad * @start: Start address (page-based, not byte-based) 88 1.1 riastrad * @pages: Size of object (page-based) 89 1.1 riastrad * 90 1.2 riastrad * Same as drm_vma_offset_lookup_locked() but does not allow any offset into the node. 91 1.1 riastrad * It only returns the exact object with the given start address. 92 1.1 riastrad * 93 1.1 riastrad * RETURNS: 94 1.1 riastrad * Node at exact start address @start. 95 1.1 riastrad */ 96 1.1 riastrad static inline struct drm_vma_offset_node * 97 1.2 riastrad drm_vma_offset_exact_lookup_locked(struct drm_vma_offset_manager *mgr, 98 1.2 riastrad unsigned long start, 99 1.2 riastrad unsigned long pages) 100 1.1 riastrad { 101 1.1 riastrad struct drm_vma_offset_node *node; 102 1.1 riastrad 103 1.2 riastrad node = drm_vma_offset_lookup_locked(mgr, start, pages); 104 1.1 riastrad return (node && node->vm_node.start == start) ? node : NULL; 105 1.1 riastrad } 106 1.1 riastrad 107 1.1 riastrad /** 108 1.1 riastrad * drm_vma_offset_lock_lookup() - Lock lookup for extended private use 109 1.1 riastrad * @mgr: Manager object 110 1.1 riastrad * 111 1.2 riastrad * Lock VMA manager for extended lookups. Only locked VMA function calls 112 1.1 riastrad * are allowed while holding this lock. All other contexts are blocked from VMA 113 1.1 riastrad * until the lock is released via drm_vma_offset_unlock_lookup(). 114 1.1 riastrad * 115 1.1 riastrad * Use this if you need to take a reference to the objects returned by 116 1.1 riastrad * drm_vma_offset_lookup_locked() before releasing this lock again. 117 1.1 riastrad * 118 1.1 riastrad * This lock must not be used for anything else than extended lookups. You must 119 1.1 riastrad * not call any other VMA helpers while holding this lock. 120 1.1 riastrad * 121 1.1 riastrad * Note: You're in atomic-context while holding this lock! 122 1.1 riastrad */ 123 1.1 riastrad static inline void drm_vma_offset_lock_lookup(struct drm_vma_offset_manager *mgr) 124 1.1 riastrad { 125 1.1 riastrad read_lock(&mgr->vm_lock); 126 1.1 riastrad } 127 1.1 riastrad 128 1.1 riastrad /** 129 1.1 riastrad * drm_vma_offset_unlock_lookup() - Unlock lookup for extended private use 130 1.1 riastrad * @mgr: Manager object 131 1.1 riastrad * 132 1.1 riastrad * Release lookup-lock. See drm_vma_offset_lock_lookup() for more information. 133 1.1 riastrad */ 134 1.1 riastrad static inline void drm_vma_offset_unlock_lookup(struct drm_vma_offset_manager *mgr) 135 1.1 riastrad { 136 1.1 riastrad read_unlock(&mgr->vm_lock); 137 1.1 riastrad } 138 1.1 riastrad 139 1.1 riastrad /** 140 1.1 riastrad * drm_vma_node_reset() - Initialize or reset node object 141 1.1 riastrad * @node: Node to initialize or reset 142 1.1 riastrad * 143 1.1 riastrad * Reset a node to its initial state. This must be called before using it with 144 1.1 riastrad * any VMA offset manager. 145 1.1 riastrad * 146 1.1 riastrad * This must not be called on an already allocated node, or you will leak 147 1.1 riastrad * memory. 148 1.1 riastrad */ 149 1.1 riastrad static inline void drm_vma_node_reset(struct drm_vma_offset_node *node) 150 1.1 riastrad { 151 1.1 riastrad memset(node, 0, sizeof(*node)); 152 1.1 riastrad node->vm_files = RB_ROOT; 153 1.1 riastrad rwlock_init(&node->vm_lock); 154 1.1 riastrad } 155 1.1 riastrad 156 1.1 riastrad /** 157 1.1 riastrad * drm_vma_node_start() - Return start address for page-based addressing 158 1.1 riastrad * @node: Node to inspect 159 1.1 riastrad * 160 1.1 riastrad * Return the start address of the given node. This can be used as offset into 161 1.1 riastrad * the linear VM space that is provided by the VMA offset manager. Note that 162 1.1 riastrad * this can only be used for page-based addressing. If you need a proper offset 163 1.1 riastrad * for user-space mappings, you must apply "<< PAGE_SHIFT" or use the 164 1.1 riastrad * drm_vma_node_offset_addr() helper instead. 165 1.1 riastrad * 166 1.1 riastrad * RETURNS: 167 1.1 riastrad * Start address of @node for page-based addressing. 0 if the node does not 168 1.1 riastrad * have an offset allocated. 169 1.1 riastrad */ 170 1.3 riastrad static inline unsigned long drm_vma_node_start(const struct drm_vma_offset_node *node) 171 1.1 riastrad { 172 1.1 riastrad return node->vm_node.start; 173 1.1 riastrad } 174 1.1 riastrad 175 1.1 riastrad /** 176 1.1 riastrad * drm_vma_node_size() - Return size (page-based) 177 1.1 riastrad * @node: Node to inspect 178 1.1 riastrad * 179 1.1 riastrad * Return the size as number of pages for the given node. This is the same size 180 1.1 riastrad * that was passed to drm_vma_offset_add(). If no offset is allocated for the 181 1.1 riastrad * node, this is 0. 182 1.1 riastrad * 183 1.1 riastrad * RETURNS: 184 1.1 riastrad * Size of @node as number of pages. 0 if the node does not have an offset 185 1.1 riastrad * allocated. 186 1.1 riastrad */ 187 1.1 riastrad static inline unsigned long drm_vma_node_size(struct drm_vma_offset_node *node) 188 1.1 riastrad { 189 1.1 riastrad return node->vm_node.size; 190 1.1 riastrad } 191 1.1 riastrad 192 1.1 riastrad /** 193 1.1 riastrad * drm_vma_node_offset_addr() - Return sanitized offset for user-space mmaps 194 1.1 riastrad * @node: Linked offset node 195 1.1 riastrad * 196 1.1 riastrad * Same as drm_vma_node_start() but returns the address as a valid offset that 197 1.1 riastrad * can be used for user-space mappings during mmap(). 198 1.1 riastrad * This must not be called on unlinked nodes. 199 1.1 riastrad * 200 1.1 riastrad * RETURNS: 201 1.1 riastrad * Offset of @node for byte-based addressing. 0 if the node does not have an 202 1.1 riastrad * object allocated. 203 1.1 riastrad */ 204 1.1 riastrad static inline __u64 drm_vma_node_offset_addr(struct drm_vma_offset_node *node) 205 1.1 riastrad { 206 1.1 riastrad return ((__u64)node->vm_node.start) << PAGE_SHIFT; 207 1.1 riastrad } 208 1.1 riastrad 209 1.1 riastrad /** 210 1.1 riastrad * drm_vma_node_unmap() - Unmap offset node 211 1.1 riastrad * @node: Offset node 212 1.1 riastrad * @file_mapping: Address space to unmap @node from 213 1.1 riastrad * 214 1.1 riastrad * Unmap all userspace mappings for a given offset node. The mappings must be 215 1.1 riastrad * associated with the @file_mapping address-space. If no offset exists 216 1.1 riastrad * nothing is done. 217 1.1 riastrad * 218 1.1 riastrad * This call is unlocked. The caller must guarantee that drm_vma_offset_remove() 219 1.1 riastrad * is not called on this node concurrently. 220 1.1 riastrad */ 221 1.1 riastrad static inline void drm_vma_node_unmap(struct drm_vma_offset_node *node, 222 1.1 riastrad struct address_space *file_mapping) 223 1.1 riastrad { 224 1.3 riastrad if (drm_mm_node_allocated(&node->vm_node)) 225 1.1 riastrad unmap_mapping_range(file_mapping, 226 1.1 riastrad drm_vma_node_offset_addr(node), 227 1.1 riastrad drm_vma_node_size(node) << PAGE_SHIFT, 1); 228 1.1 riastrad } 229 1.1 riastrad 230 1.1 riastrad /** 231 1.1 riastrad * drm_vma_node_verify_access() - Access verification helper for TTM 232 1.1 riastrad * @node: Offset node 233 1.3 riastrad * @tag: Tag of file to check 234 1.1 riastrad * 235 1.3 riastrad * This checks whether @tag is granted access to @node. It is the same as 236 1.1 riastrad * drm_vma_node_is_allowed() but suitable as drop-in helper for TTM 237 1.1 riastrad * verify_access() callbacks. 238 1.1 riastrad * 239 1.1 riastrad * RETURNS: 240 1.1 riastrad * 0 if access is granted, -EACCES otherwise. 241 1.1 riastrad */ 242 1.1 riastrad static inline int drm_vma_node_verify_access(struct drm_vma_offset_node *node, 243 1.3 riastrad struct drm_file *tag) 244 1.1 riastrad { 245 1.3 riastrad return drm_vma_node_is_allowed(node, tag) ? 0 : -EACCES; 246 1.1 riastrad } 247 1.1 riastrad 248 1.1 riastrad #endif /* __DRM_VMA_MANAGER_H__ */ 249