|
| 1 | +/* SPDX-License-Identifier: GPL-2.0 */ |
| 2 | +/* Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES. |
| 3 | + * |
| 4 | + */ |
| 5 | +#ifndef __IO_PAGETABLE_H |
| 6 | +#define __IO_PAGETABLE_H |
| 7 | + |
| 8 | +#include <linux/interval_tree.h> |
| 9 | +#include <linux/mutex.h> |
| 10 | +#include <linux/kref.h> |
| 11 | +#include <linux/xarray.h> |
| 12 | + |
| 13 | +#include "iommufd_private.h" |
| 14 | + |
| 15 | +struct iommu_domain; |
| 16 | + |
| 17 | +/* |
| 18 | + * Each io_pagetable is composed of intervals of areas which cover regions of |
| 19 | + * the iova that are backed by something. iova not covered by areas is not |
| 20 | + * populated in the page table. Each area is fully populated with pages. |
| 21 | + * |
| 22 | + * iovas are in byte units, but must be iopt->iova_alignment aligned. |
| 23 | + * |
| 24 | + * pages can be NULL, this means some other thread is still working on setting |
| 25 | + * up or tearing down the area. When observed under the write side of the |
| 26 | + * domain_rwsem a NULL pages must mean the area is still being setup and no |
| 27 | + * domains are filled. |
| 28 | + * |
| 29 | + * storage_domain points at an arbitrary iommu_domain that is holding the PFNs |
| 30 | + * for this area. It is locked by the pages->mutex. This simplifies the locking |
| 31 | + * as the pages code can rely on the storage_domain without having to get the |
| 32 | + * iopt->domains_rwsem. |
| 33 | + * |
| 34 | + * The io_pagetable::iova_rwsem protects node |
| 35 | + * The iopt_pages::mutex protects pages_node |
| 36 | + * iopt and immu_prot are immutable |
| 37 | + * The pages::mutex protects num_accesses |
| 38 | + */ |
| 39 | +struct iopt_area { |
| 40 | + struct interval_tree_node node; |
| 41 | + struct interval_tree_node pages_node; |
| 42 | + struct io_pagetable *iopt; |
| 43 | + struct iopt_pages *pages; |
| 44 | + struct iommu_domain *storage_domain; |
| 45 | + /* How many bytes into the first page the area starts */ |
| 46 | + unsigned int page_offset; |
| 47 | + /* IOMMU_READ, IOMMU_WRITE, etc */ |
| 48 | + int iommu_prot; |
| 49 | + unsigned int num_accesses; |
| 50 | +}; |
| 51 | + |
| 52 | +static inline unsigned long iopt_area_index(struct iopt_area *area) |
| 53 | +{ |
| 54 | + return area->pages_node.start; |
| 55 | +} |
| 56 | + |
| 57 | +static inline unsigned long iopt_area_last_index(struct iopt_area *area) |
| 58 | +{ |
| 59 | + return area->pages_node.last; |
| 60 | +} |
| 61 | + |
| 62 | +static inline unsigned long iopt_area_iova(struct iopt_area *area) |
| 63 | +{ |
| 64 | + return area->node.start; |
| 65 | +} |
| 66 | + |
| 67 | +static inline unsigned long iopt_area_last_iova(struct iopt_area *area) |
| 68 | +{ |
| 69 | + return area->node.last; |
| 70 | +} |
| 71 | + |
| 72 | +enum { |
| 73 | + IOPT_PAGES_ACCOUNT_NONE = 0, |
| 74 | + IOPT_PAGES_ACCOUNT_USER = 1, |
| 75 | + IOPT_PAGES_ACCOUNT_MM = 2, |
| 76 | +}; |
| 77 | + |
| 78 | +/* |
| 79 | + * This holds a pinned page list for multiple areas of IO address space. The |
| 80 | + * pages always originate from a linear chunk of userspace VA. Multiple |
| 81 | + * io_pagetable's, through their iopt_area's, can share a single iopt_pages |
| 82 | + * which avoids multi-pinning and double accounting of page consumption. |
| 83 | + * |
| 84 | + * indexes in this structure are measured in PAGE_SIZE units, are 0 based from |
| 85 | + * the start of the uptr and extend to npages. pages are pinned dynamically |
| 86 | + * according to the intervals in the access_itree and domains_itree, npinned |
| 87 | + * records the current number of pages pinned. |
| 88 | + */ |
| 89 | +struct iopt_pages { |
| 90 | + struct kref kref; |
| 91 | + struct mutex mutex; |
| 92 | + size_t npages; |
| 93 | + size_t npinned; |
| 94 | + size_t last_npinned; |
| 95 | + struct task_struct *source_task; |
| 96 | + struct mm_struct *source_mm; |
| 97 | + struct user_struct *source_user; |
| 98 | + void __user *uptr; |
| 99 | + bool writable:1; |
| 100 | + u8 account_mode; |
| 101 | + |
| 102 | + struct xarray pinned_pfns; |
| 103 | + /* Of iopt_pages_access::node */ |
| 104 | + struct rb_root_cached access_itree; |
| 105 | + /* Of iopt_area::pages_node */ |
| 106 | + struct rb_root_cached domains_itree; |
| 107 | +}; |
| 108 | + |
| 109 | +#endif |
0 commit comments