1 /******************************************************************************* 2 Copyright (c) 2022-2023 NVIDIA Corporation 3 4 Permission is hereby granted, free of charge, to any person obtaining a copy 5 of this software and associated documentation files (the "Software"), to 6 deal in the Software without restriction, including without limitation the 7 rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 sell copies of the Software, and to permit persons to whom the Software is 9 furnished to do so, subject to the following conditions: 10 11 The above copyright notice and this permission notice shall be 12 included in all copies or substantial portions of the Software. 13 14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 DEALINGS IN THE SOFTWARE. 21 22 *******************************************************************************/ 23 24 #ifndef __UVM_VA_POLICY_H__ 25 #define __UVM_VA_POLICY_H__ 26 27 #include <linux/numa.h> 28 #include "uvm_linux.h" 29 #include "uvm_forward_decl.h" 30 #include "uvm_processors.h" 31 #include "uvm_range_tree.h" 32 #include "uvm_va_block_types.h" 33 34 // This enum must be kept in sync with UVM_TEST_READ_DUPLICATION_POLICY in 35 // uvm_test_ioctl.h 36 typedef enum 37 { 38 UVM_READ_DUPLICATION_UNSET = 0, 39 UVM_READ_DUPLICATION_ENABLED, 40 UVM_READ_DUPLICATION_DISABLED, 41 UVM_READ_DUPLICATION_MAX 42 } uvm_read_duplication_policy_t; 43 44 typedef enum 45 { 46 UVM_VA_POLICY_PREFERRED_LOCATION = 0, 47 UVM_VA_POLICY_ACCESSED_BY, 48 UVM_VA_POLICY_READ_DUPLICATION, 49 } uvm_va_policy_type_t; 50 51 // 52 // A policy covers one or more contiguous Linux VMAs or portion of a VMA and 53 // does not cover non-existant VMAs. 54 // The VA range is determined from either the uvm_va_range_t for managed 55 // allocations or the uvm_va_policy_node_t for HMM allocations. 56 // 57 struct uvm_va_policy_struct 58 { 59 // Read duplication policy for this VA range (unset, enabled, or disabled). 60 uvm_read_duplication_policy_t read_duplication; 61 62 // Processor ID of the preferred location for this VA range. 63 // This is set to UVM_ID_INVALID if no preferred location is set. 64 uvm_processor_id_t preferred_location; 65 66 // If the preferred location is the CPU, this is either the preferred NUMA 67 // node ID or NUMA_NO_NODE to indicate that there is no preference among 68 // nodes. 69 // If preferred_location is a GPU, preferred_nid will be used if CPU 70 // pages have to be allocated for any staging copies. Otherwise, it is 71 // not used. 72 // 73 // TODO: Bug 4148100 - Preferred_location and preferred_nid should be 74 // combined into a new type that combines the processor and NUMA node 75 // ID. 76 int preferred_nid; 77 78 // Mask of processors that are accessing this VA range and should have 79 // their page tables updated to access the (possibly remote) pages. 80 uvm_processor_mask_t accessed_by; 81 82 }; 83 84 // Policy nodes are used for storing policies in HMM va_blocks. 85 // The va_block lock protects the tree so that invalidation callbacks can 86 // update the VA policy tree. 87 typedef struct uvm_va_policy_node_struct 88 { 89 // Storage for the policy tree node. It also contains the range start and 90 // end. Start and end + 1 have to be PAGE_SIZED aligned. 91 uvm_range_tree_node_t node; 92 93 uvm_va_policy_t policy; 94 95 } uvm_va_policy_node_t; 96 97 // Function pointer prototype for uvm_hmm_split_as_needed() callback. 98 typedef bool (*uvm_va_policy_is_split_needed_t)(const uvm_va_policy_t *policy, void *data); 99 100 // Default policy to save uvm_va_policy_node_t space in HMM va_blocks. 101 extern const uvm_va_policy_t uvm_va_policy_default; 102 103 // Return true if policy is the default policy. 104 static bool uvm_va_policy_is_default(const uvm_va_policy_t *policy) 105 { 106 return policy == &uvm_va_policy_default; 107 } 108 109 bool uvm_va_policy_is_read_duplicate(const uvm_va_policy_t *policy, uvm_va_space_t *va_space); 110 111 // Returns the uvm_va_policy_t containing addr or default policy if not found. 112 // The va_block can be either a UVM or HMM va_block. 113 // Locking: The va_block lock must be held. 114 const uvm_va_policy_t *uvm_va_policy_get(uvm_va_block_t *va_block, NvU64 addr); 115 116 // Same as above but asserts the policy covers the whole region 117 const uvm_va_policy_t *uvm_va_policy_get_region(uvm_va_block_t *va_block, uvm_va_block_region_t region); 118 119 // Return a uvm_va_policy_node_t given a uvm_va_policy_t pointer. 120 static const uvm_va_policy_node_t *uvm_va_policy_node_from_policy(const uvm_va_policy_t *policy) 121 { 122 return container_of(policy, uvm_va_policy_node_t, policy); 123 } 124 125 #if UVM_IS_CONFIG_HMM() 126 127 // Module load/exit 128 NV_STATUS uvm_va_policy_init(void); 129 void uvm_va_policy_exit(void); 130 131 // Returns the uvm_va_policy_node_t containing addr or NULL if not found. 132 // The va_block must be a HMM va_block. 133 // Locking: The va_block lock must be held. 134 uvm_va_policy_node_t *uvm_va_policy_node_find(uvm_va_block_t *va_block, NvU64 addr); 135 136 // Split the old node. The old node will end at 'new_end' and the new node will 137 // start at 'new_end' + 1 and end at old end. 138 // The va_block must be a HMM va_block. 139 // Locking: The va_block lock must be held. 140 NV_STATUS uvm_va_policy_node_split(uvm_va_block_t *va_block, 141 uvm_va_policy_node_t *old, 142 NvU64 new_end, 143 uvm_va_policy_node_t **new_ptr); 144 145 // Move hints from 'old' to 'new' which must both be HMM va_blocks. 146 // The old va_block policies should have been pre-split and since we don't 147 // merge policy ranges, they should still be split after locking/unlocking 148 // 'old'. This should be called after splitting a block. 149 // TODO: Bug 1707562: Add support for merging policy ranges. 150 // Locking: The va_block lock must be held for both old and new. 151 void uvm_va_policy_node_split_move(uvm_va_block_t *old_va_block, 152 uvm_va_block_t *new_va_block); 153 154 // Remove all policy in the given range start/end where 'end' is inclusive. 155 // This function may clear a range larger than start/end if clearing the range 156 // requires memory allocation and the memory allocation fails. 157 // The va_block must be a HMM va_block. 158 // Locking: The va_block lock must be held. 159 void uvm_va_policy_clear(uvm_va_block_t *va_block, NvU64 start, NvU64 end); 160 161 // Fill in any missing policy nodes for the given range and set the policy 162 // to the given value. The caller is expected to split any policy nodes 163 // before calling this function so the range being set does not. 164 // The va_block must be a HMM va_block. 165 // Note that start and end + 1 must be page aligned, 'end' is inclusive. 166 // TODO: Bug 1707562: Add support for merging policy ranges. 167 // Locking: The va_block lock must be held. 168 NV_STATUS uvm_va_policy_set_range(uvm_va_block_t *va_block, 169 NvU64 start, 170 NvU64 end, 171 uvm_va_policy_type_t which, 172 bool is_default, 173 uvm_processor_id_t processor_id, 174 uvm_read_duplication_policy_t new_policy); 175 176 // This is an optimized version of uvm_va_policy_set_range() where the caller 177 // guarantees that the the processor_id is not the same as the existing 178 // policy for the given region and that the region doesn't require splitting 179 // the existing policy node 'old_policy'. 180 // Returns the updated policy or NULL if memory could not be allocated. 181 // Locking: The va_block lock must be held. 182 const uvm_va_policy_t *uvm_va_policy_set_preferred_location(uvm_va_block_t *va_block, 183 uvm_va_block_region_t region, 184 uvm_processor_id_t processor_id, 185 const uvm_va_policy_t *old_policy); 186 187 // Iterators for specific VA policy ranges. 188 189 // Returns the first policy node in the range [start, end], if any. 190 // The va_block must be a HMM va_block. 191 // Locking: The va_block lock must be held. 192 uvm_va_policy_node_t *uvm_va_policy_node_iter_first(uvm_va_block_t *va_block, NvU64 start, NvU64 end); 193 194 // Returns the next VA policy following the provided policy in address order, 195 // if that policy's start <= the provided end. 196 // The va_block must be a HMM va_block. 197 // Locking: The va_block lock must be held. 198 uvm_va_policy_node_t *uvm_va_policy_node_iter_next(uvm_va_block_t *va_block, uvm_va_policy_node_t *node, NvU64 end); 199 200 #define uvm_for_each_va_policy_node_in(node, va_block, start, end) \ 201 for ((node) = uvm_va_policy_node_iter_first((va_block), (start), (end)); \ 202 (node); \ 203 (node) = uvm_va_policy_node_iter_next((va_block), (node), (end))) 204 205 #define uvm_for_each_va_policy_node_in_safe(node, next, va_block, start, end) \ 206 for ((node) = uvm_va_policy_node_iter_first((va_block), (start), (end)), \ 207 (next) = uvm_va_policy_node_iter_next((va_block), (node), (end)); \ 208 (node); \ 209 (node) = (next), \ 210 (next) = uvm_va_policy_node_iter_next((va_block), (node), (end))) 211 212 // Returns the first policy in the range [start, end], if any. 213 // Locking: The va_block lock must be held. 214 const uvm_va_policy_t *uvm_va_policy_iter_first(uvm_va_block_t *va_block, 215 NvU64 start, 216 NvU64 end, 217 uvm_va_policy_node_t **out_node, 218 uvm_va_block_region_t *out_region); 219 220 // Returns the next VA policy following the provided policy in address order, 221 // if that policy's start <= the provided end. 222 // Locking: The va_block lock must be held. 223 const uvm_va_policy_t *uvm_va_policy_iter_next(uvm_va_block_t *va_block, 224 const uvm_va_policy_t *policy, 225 NvU64 end, 226 uvm_va_policy_node_t **inout_node, 227 uvm_va_block_region_t *inout_region); 228 229 // Note that policy and region are set and usable in the loop body. 230 // The 'node' variable is used to retain loop state and 'policy' doesn't 231 // necessarily match &node->policy. 232 #define uvm_for_each_va_policy_in(policy, va_block, start, end, node, region) \ 233 for ((policy) = uvm_va_policy_iter_first((va_block), (start), (end), &(node), &(region)); \ 234 (policy); \ 235 (policy) = uvm_va_policy_iter_next((va_block), (policy), (end), &(node), &(region))) 236 237 #else // UVM_IS_CONFIG_HMM() 238 239 static NV_STATUS uvm_va_policy_init(void) 240 { 241 return NV_OK; 242 } 243 244 static void uvm_va_policy_exit(void) 245 { 246 } 247 248 static uvm_va_policy_node_t *uvm_va_policy_node_find(uvm_va_block_t *va_block, NvU64 addr) 249 { 250 UVM_ASSERT(0); 251 return NULL; 252 } 253 254 static NV_STATUS uvm_va_policy_node_split(uvm_va_block_t *va_block, 255 uvm_va_policy_node_t *old, 256 NvU64 new_end, 257 uvm_va_policy_node_t **new_ptr) 258 { 259 return NV_OK; 260 } 261 262 static void uvm_va_policy_node_split_move(uvm_va_block_t *old_va_block, 263 uvm_va_block_t *new_va_block) 264 { 265 } 266 267 static void uvm_va_policy_clear(uvm_va_block_t *va_block, NvU64 start, NvU64 end) 268 { 269 } 270 271 static NV_STATUS uvm_va_policy_set_range(uvm_va_block_t *va_block, 272 NvU64 start, 273 NvU64 end, 274 uvm_va_policy_type_t which, 275 bool is_default, 276 uvm_processor_id_t processor_id, 277 uvm_read_duplication_policy_t new_policy) 278 { 279 return NV_OK; 280 } 281 282 static uvm_va_policy_node_t *uvm_va_policy_node_iter_first(uvm_va_block_t *va_block, NvU64 start, NvU64 end) 283 { 284 return NULL; 285 } 286 287 #endif // UVM_IS_CONFIG_HMM() 288 289 #endif // __UVM_VA_POLICY_H__ 290