1 /*******************************************************************************
2     Copyright (c) 2017-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_PMM_SYSMEM_H__
25 #define __UVM_PMM_SYSMEM_H__
26 
27 #include "uvm_common.h"
28 #include "uvm_linux.h"
29 #include "uvm_forward_decl.h"
30 #include "uvm_lock.h"
31 #include "uvm_pmm_gpu.h"
32 
33 // Module to handle per-GPU user mappings to sysmem physical memory. Notably,
34 // this implements a reverse map of the DMA address to {va_block, virt_addr}.
35 // This is required by the GPU access counters feature since they may provide a
36 // physical address in the notification packet (GPA notifications). We use the
37 // table to obtain the VAs of the memory regions being accessed remotely. The
38 // reverse map is implemented by a radix tree, which is indexed using the
39 // DMA address. For now, only PAGE_SIZE translations are supported (i.e. no
40 // big/huge pages).
41 //
42 // TODO: Bug 1995015: add support for physically-contiguous mappings.
43 struct uvm_pmm_sysmem_mappings_struct
44 {
45     uvm_gpu_t                                      *gpu;
46 
47     struct radix_tree_root             reverse_map_tree;
48 
49     uvm_mutex_t                        reverse_map_lock;
50 };
51 
52 // See comments in uvm_linux.h
53 #ifdef NV_RADIX_TREE_REPLACE_SLOT_PRESENT
54 #define uvm_pmm_sysmem_mappings_indirect_supported() true
55 #else
56 #define uvm_pmm_sysmem_mappings_indirect_supported() false
57 #endif
58 
59 // Global initialization/exit functions, that need to be called during driver
60 // initialization/tear-down. These are needed to allocate/free global internal
61 // data structures.
62 NV_STATUS uvm_pmm_sysmem_init(void);
63 void uvm_pmm_sysmem_exit(void);
64 
65 // Initialize per-GPU sysmem mapping tracking
66 NV_STATUS uvm_pmm_sysmem_mappings_init(uvm_gpu_t *gpu, uvm_pmm_sysmem_mappings_t *sysmem_mappings);
67 
68 // Destroy per-GPU sysmem mapping tracking. The caller must ensure that all the
69 // mappings have been removed before calling this function.
70 void uvm_pmm_sysmem_mappings_deinit(uvm_pmm_sysmem_mappings_t *sysmem_mappings);
71 
72 // If the GPU used to initialize sysmem_mappings supports access counters, the
73 // dma_addr -> {va_block, virt_addr} mapping is inserted in the reverse map.
74 NV_STATUS uvm_pmm_sysmem_mappings_add_gpu_mapping(uvm_pmm_sysmem_mappings_t *sysmem_mappings,
75                                                   NvU64 dma_addr,
76                                                   NvU64 virt_addr,
77                                                   NvU64 region_size,
78                                                   uvm_va_block_t *va_block,
79                                                   uvm_processor_id_t owner);
80 
uvm_pmm_sysmem_mappings_add_gpu_chunk_mapping(uvm_pmm_sysmem_mappings_t * sysmem_mappings,NvU64 dma_addr,NvU64 virt_addr,NvU64 region_size,uvm_va_block_t * va_block,uvm_gpu_id_t owner)81 static NV_STATUS uvm_pmm_sysmem_mappings_add_gpu_chunk_mapping(uvm_pmm_sysmem_mappings_t *sysmem_mappings,
82                                                                NvU64 dma_addr,
83                                                                NvU64 virt_addr,
84                                                                NvU64 region_size,
85                                                                uvm_va_block_t *va_block,
86                                                                uvm_gpu_id_t owner)
87 {
88     if (!uvm_pmm_sysmem_mappings_indirect_supported())
89         return NV_OK;
90 
91     return uvm_pmm_sysmem_mappings_add_gpu_mapping(sysmem_mappings,
92                                                    dma_addr,
93                                                    virt_addr,
94                                                    region_size,
95                                                    va_block,
96                                                    owner);
97 }
98 
99 // If the GPU used to initialize sysmem_mappings supports access counters, the
100 // entries for the physical region starting at dma_addr are removed from the
101 // reverse map.
102 void uvm_pmm_sysmem_mappings_remove_gpu_mapping(uvm_pmm_sysmem_mappings_t *sysmem_mappings, NvU64 dma_addr);
103 
uvm_pmm_sysmem_mappings_remove_gpu_chunk_mapping(uvm_pmm_sysmem_mappings_t * sysmem_mappings,NvU64 dma_addr)104 static void uvm_pmm_sysmem_mappings_remove_gpu_chunk_mapping(uvm_pmm_sysmem_mappings_t *sysmem_mappings, NvU64 dma_addr)
105 {
106     if (uvm_pmm_sysmem_mappings_indirect_supported())
107         uvm_pmm_sysmem_mappings_remove_gpu_mapping(sysmem_mappings, dma_addr);
108 }
109 
110 // Like uvm_pmm_sysmem_mappings_remove_gpu_mapping but it doesn't assert if the
111 // mapping doesn't exist. See uvm_va_block_evict_chunks for more information.
112 void uvm_pmm_sysmem_mappings_remove_gpu_mapping_on_eviction(uvm_pmm_sysmem_mappings_t *sysmem_mappings, NvU64 dma_addr);
113 
114 // If the GPU used to initialize sysmem_mappings supports access counters, the
115 // mapping for the region starting at dma_addr is updated with va_block.
116 // This is required on VA block split.
117 void uvm_pmm_sysmem_mappings_reparent_gpu_mapping(uvm_pmm_sysmem_mappings_t *sysmem_mappings,
118                                                   NvU64 dma_addr,
119                                                   uvm_va_block_t *va_block);
120 
uvm_pmm_sysmem_mappings_reparent_gpu_chunk_mapping(uvm_pmm_sysmem_mappings_t * sysmem_mappings,NvU64 dma_addr,uvm_va_block_t * va_block)121 static void uvm_pmm_sysmem_mappings_reparent_gpu_chunk_mapping(uvm_pmm_sysmem_mappings_t *sysmem_mappings,
122                                                                NvU64 dma_addr,
123                                                                uvm_va_block_t *va_block)
124 {
125     if (uvm_pmm_sysmem_mappings_indirect_supported())
126         uvm_pmm_sysmem_mappings_reparent_gpu_mapping(sysmem_mappings, dma_addr, va_block);
127 }
128 
129 // If the GPU used to initialize sysmem_mappings supports access counters, the
130 // mapping for the region starting at dma_addr is split into regions of
131 // new_region_size. new_region_size must be a power of two and smaller than the
132 // previously-registered size.
133 NV_STATUS uvm_pmm_sysmem_mappings_split_gpu_mappings(uvm_pmm_sysmem_mappings_t *sysmem_mappings,
134                                                      NvU64 dma_addr,
135                                                      NvU64 new_region_size);
136 
uvm_pmm_sysmem_mappings_split_gpu_chunk_mappings(uvm_pmm_sysmem_mappings_t * sysmem_mappings,NvU64 dma_addr,NvU64 new_region_size)137 static NV_STATUS uvm_pmm_sysmem_mappings_split_gpu_chunk_mappings(uvm_pmm_sysmem_mappings_t *sysmem_mappings,
138                                                                   NvU64 dma_addr,
139                                                                   NvU64 new_region_size)
140 {
141     if (!uvm_pmm_sysmem_mappings_indirect_supported())
142         return NV_OK;
143 
144     return uvm_pmm_sysmem_mappings_split_gpu_mappings(sysmem_mappings, dma_addr, new_region_size);
145 }
146 
147 // If the GPU used to initialize sysmem_mappings supports access counters, all
148 // the mappings within the region [dma_addr, dma_addr + new_region_size) are
149 // merged into a single mapping. new_region_size must be a power of two. The
150 // whole region must be previously populated with mappings and all of them must
151 // have the same VA block and processor owner.
152 void uvm_pmm_sysmem_mappings_merge_gpu_mappings(uvm_pmm_sysmem_mappings_t *sysmem_mappings,
153                                                 NvU64 dma_addr,
154                                                 NvU64 new_region_size);
155 
uvm_pmm_sysmem_mappings_merge_gpu_chunk_mappings(uvm_pmm_sysmem_mappings_t * sysmem_mappings,NvU64 dma_addr,NvU64 new_region_size)156 static void uvm_pmm_sysmem_mappings_merge_gpu_chunk_mappings(uvm_pmm_sysmem_mappings_t *sysmem_mappings,
157                                                              NvU64 dma_addr,
158                                                              NvU64 new_region_size)
159 {
160     if (uvm_pmm_sysmem_mappings_indirect_supported())
161         uvm_pmm_sysmem_mappings_merge_gpu_mappings(sysmem_mappings, dma_addr, new_region_size);
162 }
163 
164 // Obtain the {va_block, virt_addr} information for the mappings in the given
165 // [dma_addr:dma_addr + region_size) range. dma_addr and region_size must be
166 // page-aligned.
167 //
168 // Valid translations are written to out_mappings sequentially (there are no
169 // gaps). max_out_mappings are written, at most. The caller is required to
170 // provide enough entries in out_mappings.
171 //
172 // The VA Block in each returned translation entry is retained, and it's up to
173 // the caller to release them
174 size_t uvm_pmm_sysmem_mappings_dma_to_virt(uvm_pmm_sysmem_mappings_t *sysmem_mappings,
175                                            NvU64 dma_addr,
176                                            NvU64 region_size,
177                                            uvm_reverse_map_t *out_mappings,
178                                            size_t max_out_mappings);
179 
180 #define UVM_CPU_CHUNK_SIZES (UVM_PAGE_SIZE_2M | UVM_PAGE_SIZE_64K | PAGE_SIZE)
181 
182 typedef enum
183 {
184     UVM_CPU_CHUNK_ALLOC_FLAGS_NONE = 0,
185 
186     // Zero the chunk.
187     UVM_CPU_CHUNK_ALLOC_FLAGS_ZERO = (1 << 0),
188 
189     // Account for the chunk in the cgroup context.
190     UVM_CPU_CHUNK_ALLOC_FLAGS_ACCOUNT = (1 << 1),
191 
192     // Be strict about NUMA locality of the allocation.
193     // Attempt the allocation only on the requested NUMA
194     // node.
195     UVM_CPU_CHUNK_ALLOC_FLAGS_STRICT = (1 << 2),
196 
197     // Allow chunk allocations from ZONE_MOVABLE.
198     UVM_CPU_CHUNK_ALLOC_FLAGS_ALLOW_MOVABLE = (1 << 3),
199 } uvm_cpu_chunk_alloc_flags_t;
200 
201 typedef enum
202 {
203     UVM_CPU_CHUNK_TYPE_PHYSICAL,
204     UVM_CPU_CHUNK_TYPE_LOGICAL,
205     UVM_CPU_CHUNK_TYPE_HMM
206 } uvm_cpu_chunk_type_t;
207 
208 // CPU memory chunk descriptor.
209 // CPU memory chunks represent a physically contiguous CPU memory
210 // allocation.
211 // CPU memory chunks can be created due to CPU page allocation or
212 // CPU chunk splitting. Chunks created due to page allocations are
213 // referred to as "physical chunks", while chunks resulting from
214 // splitting are referred to as "logical chunks".
215 struct uvm_cpu_chunk_struct
216 {
217     uvm_cpu_chunk_type_t type:2;
218 
219     // Size of the chunk.
220     // For chunks resulting from page allocations (physical chunks),
221     // this value is the size of the physical allocation.
222     size_t log2_size : order_base_2(UVM_CHUNK_SIZE_MASK_SIZE);
223 
224     // Chunk reference count used when a CPU chunk is split. Each
225     // child sub-chunk will increment the reference count of its
226     // parent.
227     // The reference count is set to 1 when the chunk is created.
228     // This initial reference is dropped if the chunk is split in
229     // order to automatically destroy the chunk when all logical
230     // chunks resulting from the split are destroyed.
231     nv_kref_t refcount;
232 
233     // Pointer to the CPU page backing this CPU chunk.
234     // For physical chunks, this will point to the head page. Physical
235     // chunk allocation will set the reference count for the struct
236     // page (compound or not) to 1.
237     //
238     // For logical chunks, this will point to the struct page from
239     // the compound page array corresponding to the correct page index.
240     // Because freeing a logical chunk does not result in freeing of
241     // any struct page(s) and both physical and logical chunks are
242     // reference counted, there is no need to take separate references
243     // to the struct page for logical chunks.
244     struct page *page;
245 };
246 
247 typedef struct
248 {
249     NvU64 dma_addr;
250     NvU32 map_count;
251 } uvm_cpu_phys_mapping_t;
252 
253 typedef struct
254 {
255     uvm_cpu_chunk_t common;
256 
257     // Lock protecting dirty_bitmap and gpu_mappings.
258     uvm_mutex_t lock;
259 
260     struct
261     {
262         // Per-GPU array of DMA mapping addresses for the chunk.
263         // The DMA mapping addresses for logical chunks are adjusted
264         // to the correct offset within the parent chunk.
265         union
266         {
267             uvm_cpu_phys_mapping_t static_entry;
268             uvm_cpu_phys_mapping_t *dynamic_entries;
269         };
270 
271         // Maximum number of physical mapping entries available.
272         // The initial value is 1 since the static_entry is always
273         // available.
274         // When using the dynamic_entries, it holds the size of the
275         // dynamic_entries array. This may be more than the number
276         // of GPUs with active mappings. The number of active entries
277         // is the number of set bits in dma_addrs_mask.
278         size_t max_entries;
279 
280         // The set of GPU parent ID's that have an active physical mapping.
281         // Since physical mappings are shared by all GPUs under a
282         // parent GPU, this mask only needs to track uvm_parent_gpu_t.
283         uvm_parent_processor_mask_t dma_addrs_mask;
284     } gpu_mappings;
285 
286     // A dynamically allocated bitmap (one per PAGE_SIZE page) used
287     // to track dirty state of each PAGE_SIZE page.
288     // Large CPU chunks are allocated as compound pages. For such
289     // pages, the kernel keeps dirtiness state with a single bit
290     // (in the compound page head) that covers the entire compound
291     // page.
292     //
293     // In the case of UVM-Lite GPUs, using the dirty bit of the
294     // the compound page will cause performance regression due to
295     // the copying of extra data. We mitigate this by using this
296     // bitmap to track which base pages are dirty.
297     unsigned long *dirty_bitmap;
298 
299 } uvm_cpu_physical_chunk_t;
300 
301 typedef struct
302 {
303     uvm_cpu_chunk_t common;
304 
305     // Pointer to the parent chunk (which could also be a logical chunk).
306     uvm_cpu_chunk_t *parent;
307     uvm_parent_processor_mask_t mapped_gpus;
308 } uvm_cpu_logical_chunk_t;
309 
310 // Return the set of allowed CPU chunk allocation sizes.
311 uvm_chunk_sizes_mask_t uvm_cpu_chunk_get_allocation_sizes(void);
312 
313 // Allocate a physical CPU chunk of the specified size.
314 //
315 // The nid argument is used to indicate a memory node preference. If the
316 // value is a memory node ID, the chunk allocation will be attempted on
317 // that memory node. If the chunk cannot be allocated on that memory node,
318 // it will be allocated on any memory node allowed by the process's policy.
319 //
320 // If the value of nid is a memory node ID that is not in the set of
321 // current process's allowed memory nodes, it will be allocated on one of the
322 // nodes in the allowed set.
323 //
324 // If the value of nid is NUMA_NO_NODE, the chunk will be allocated from any
325 // of the allowed memory nodes by the process policy.
326 //
327 // If a CPU chunk allocation succeeds, NV_OK is returned. new_chunk will be set
328 // to point to the newly allocated chunk. On failure, NV_ERR_NO_MEMORY is
329 // returned.
330 NV_STATUS uvm_cpu_chunk_alloc(uvm_chunk_size_t alloc_size,
331                               uvm_cpu_chunk_alloc_flags_t flags,
332                               int nid,
333                               uvm_cpu_chunk_t **new_chunk);
334 
335 // Allocate a HMM CPU chunk.
336 //
337 // HMM chunks differ from normal CPU chunks in that the kernel has already
338 // allocated the page for them. This means we don't allocate any CPU memory
339 // here. It also means the kernel holds the reference to the page, so we
340 // shouldn't call put_page() when freeing the chunk.
341 //
342 // If a CPU chunk allocation succeeds NV_OK is returned and new_chunk will be
343 // set to point to the newly allocated chunk. On failure, NV_ERR_NO_MEMORY is
344 // returned.
345 //
346 // Note that the kernel retains logical ownership of the page. This means page
347 // properties should not be directly modified by UVM. In particular page flags
348 // such as PageDirty should not be modified by UVM, nor can UVM directly free
349 // the page. The kernel is also responsible for mapping/unmapping the page on
350 // the CPU. We create a CPU chunk for the page primarily to allow GPU mappings
351 // for the page to be created.
352 NV_STATUS uvm_cpu_chunk_alloc_hmm(struct page *page,
353                                   uvm_cpu_chunk_t **new_chunk);
354 
355 // Convert a physical chunk to an HMM chunk.
uvm_cpu_chunk_make_hmm(uvm_cpu_chunk_t * chunk)356 static void uvm_cpu_chunk_make_hmm(uvm_cpu_chunk_t *chunk)
357 {
358     UVM_ASSERT(chunk->type == UVM_CPU_CHUNK_TYPE_PHYSICAL);
359 
360     chunk->type = UVM_CPU_CHUNK_TYPE_HMM;
361 }
362 
363 uvm_chunk_size_t uvm_cpu_chunk_get_size(uvm_cpu_chunk_t *chunk);
364 
365 // Return the number of base system pages covered by the CPU chunk.
uvm_cpu_chunk_num_pages(uvm_cpu_chunk_t * chunk)366 static size_t uvm_cpu_chunk_num_pages(uvm_cpu_chunk_t *chunk)
367 {
368     UVM_ASSERT(chunk);
369     return uvm_cpu_chunk_get_size(chunk) / PAGE_SIZE;
370 }
371 
uvm_cpu_chunk_is_hmm(uvm_cpu_chunk_t * chunk)372 static inline bool uvm_cpu_chunk_is_hmm(uvm_cpu_chunk_t *chunk)
373 {
374     return chunk->type == UVM_CPU_CHUNK_TYPE_HMM;
375 }
376 
uvm_cpu_chunk_is_physical(uvm_cpu_chunk_t * chunk)377 static bool uvm_cpu_chunk_is_physical(uvm_cpu_chunk_t *chunk)
378 {
379     return (chunk->type == UVM_CPU_CHUNK_TYPE_PHYSICAL || uvm_cpu_chunk_is_hmm(chunk));
380 }
381 
uvm_cpu_chunk_is_logical(uvm_cpu_chunk_t * chunk)382 static bool uvm_cpu_chunk_is_logical(uvm_cpu_chunk_t *chunk)
383 {
384     return chunk->type == UVM_CPU_CHUNK_TYPE_LOGICAL;
385 }
386 
uvm_cpu_chunk_to_physical(uvm_cpu_chunk_t * chunk)387 static uvm_cpu_physical_chunk_t *uvm_cpu_chunk_to_physical(uvm_cpu_chunk_t *chunk)
388 {
389     UVM_ASSERT(uvm_cpu_chunk_is_physical(chunk));
390     return container_of((chunk), uvm_cpu_physical_chunk_t, common);
391 }
392 
uvm_cpu_chunk_to_logical(uvm_cpu_chunk_t * chunk)393 static uvm_cpu_logical_chunk_t *uvm_cpu_chunk_to_logical(uvm_cpu_chunk_t *chunk)
394 {
395     UVM_ASSERT(uvm_cpu_chunk_is_logical(chunk));
396     return container_of((chunk), uvm_cpu_logical_chunk_t, common);
397 }
398 
399 // Return the NUMA node ID of the physical page backing the chunk.
400 int uvm_cpu_chunk_get_numa_node(uvm_cpu_chunk_t *chunk);
401 
402 // Free a CPU chunk.
403 // This may not result in the immediate freeing of the physical pages of the
404 // chunk if this is a logical chunk and there are other logical chunks holding
405 // references to the physical chunk.
406 // If any DMA mappings to this chunk are still active, they are implicitly
407 // destroyed.
408 void uvm_cpu_chunk_free(uvm_cpu_chunk_t *chunk);
409 
410 // In some configurations such as SR-IOV heavy, a CPU chunk cannot be
411 // referenced using its physical address. There needs to be a kernel virtual
412 // mapping created.
413 //
414 // This helper function creates a DMA mapping on the GPU and if necessary,
415 // a kernel virtual mapping for the chunk. The virtual mapping persists until
416 // GPU deinitialization, such that no unmap functionality is exposed.
417 // For more details see uvm_mmu_sysmem_map().
418 NV_STATUS uvm_cpu_chunk_map_gpu(uvm_cpu_chunk_t *chunk, uvm_gpu_t *gpu);
419 
420 // Destroy a CPU chunk's DMA mapping for the parent GPU.
421 // If chunk is a logical chunk, this call may not necessarily destroy the DMA
422 // mapping of the parent physical chunk since all logical chunks share the
423 // parent's DMA mapping.
424 void uvm_cpu_chunk_unmap_parent_gpu_phys(uvm_cpu_chunk_t *chunk, uvm_parent_gpu_t *parent_gpu);
425 
426 // Get the CPU chunk's DMA mapping address for the specified GPU ID.
427 // If there is no mapping for the GPU, 0 is returned.
428 NvU64 uvm_cpu_chunk_get_parent_gpu_phys_addr(uvm_cpu_chunk_t *chunk, uvm_parent_gpu_t *parent_gpu);
429 
430 // Split a CPU chunk into a set of CPU chunks of the next size down from the set
431 // of enabled CPU chunk sizes.
432 //
433 // This function expects that the chunk to be split is larger than the minimum
434 // enabled chunk size and that new_chunks has enough space for all chunks
435 // resulting from the split.
436 //
437 // On success, NV_OK is returned and the caller-provided new_chunks array will
438 // be filled out with the newly-created logical chunks.
439 //
440 // After a successfull split, the input chunk can no longer be used.
441 //
442 // On failure NV_ERR_NO_MEMORY will be returned.
443 //
444 // Should never be called for HMM chunks as these don't need splitting (they can
445 // only be PAGE_SIZE) and even if larger chunks could exist UVM could not split
446 // them without kernel interaction which currently isn't exported. Will return
447 // NV_ERR_INVALID_ARGUMENT for a HMM chunk.
448 // TODO: Bug 3368756: add support for transparent huge page (THP)
449 NV_STATUS uvm_cpu_chunk_split(uvm_cpu_chunk_t *chunk, uvm_cpu_chunk_t **new_chunks);
450 
451 // Merge an array of logical chunks into their parent chunk. All chunks have to
452 // have the same size, parent, and set of mapped GPUs.
453 uvm_cpu_chunk_t *uvm_cpu_chunk_merge(uvm_cpu_chunk_t **chunks);
454 
455 // Mark the page_index sub-page of the chunk as dirty.
456 // page_index is an offset into the chunk.
457 //
458 // Note that dirty status for HMM chunks should not be modified directly from
459 // UVM. Instead the kernel will mark the backing struct pages dirty either on
460 // fault when written to from the CPU, or when the PTE is mirrored to the GPU
461 // using hmm_range_fault().
462 void uvm_cpu_chunk_mark_dirty(uvm_cpu_chunk_t *chunk, uvm_page_index_t page_index);
463 
464 // Mark the page_index sub-page of the chunk as clean.
465 // page_index is an offset into the chunk.
466 void uvm_cpu_chunk_mark_clean(uvm_cpu_chunk_t *chunk, uvm_page_index_t page_index);
467 
468 // Return true if the page_index base page of the CPU chunk is dirty.
469 bool uvm_cpu_chunk_is_dirty(uvm_cpu_chunk_t *chunk, uvm_page_index_t page_index);
470 
uvm_test_get_cpu_chunk_allocation_sizes(UVM_TEST_GET_CPU_CHUNK_ALLOC_SIZES_PARAMS * params,struct file * filp)471 static NV_STATUS uvm_test_get_cpu_chunk_allocation_sizes(UVM_TEST_GET_CPU_CHUNK_ALLOC_SIZES_PARAMS *params,
472                                                                 struct file *filp)
473 {
474         params->alloc_size_mask = (NvU32)uvm_cpu_chunk_get_allocation_sizes();
475         return NV_OK;
476 }
477 #endif
478