Pull hmm updates from Jason Gunthorpe: "Ralph has been working on nouveau's use of hmm_range_fault() and migrate_vma() which resulted in this small series. It adds reporting of the page table order from hmm_range_fault() and some optimization of migrate_vma(): - Report the size of the page table mapping out of hmm_range_fault(). This makes it easier to establish a large/huge/etc mapping in the device's page table. - Allow devices to ignore the invalidations during migration in cases where the migration is not going to change pages. For instance migrating pages to a device does not require the device to invalidate pages already in the device. - Update nouveau and hmm_tests to use the above" * tag 'for-linus-hmm' of git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma: mm/hmm/test: use the new migration invalidation nouveau/svm: use the new migration invalidation mm/notifier: add migration invalidation type mm/migrate: add a flags parameter to migrate_vma nouveau: fix storing invalid ptes nouveau/hmm: support mapping large sysmem pages nouveau: fix mapping 2MB sysmem pages nouveau/hmm: fault one page at a time mm/hmm: add tests for hmm_pfn_to_map_order() mm/hmm: provide the page mapping order in hmm_range_fault()
Showing the changes to include/linux (3 of 14 files). Show all
Unified · Split
| @@ -37,16 +37,17 @@ · 36 unmodified lines | ||
| 37 | 37 | * will fail. Must be combined with HMM_PFN_REQ_FAULT. |
| 38 | 38 | */ |
| 39 | 39 | enum hmm_pfn_flags { |
| 40 | − /* Output flags */ | |
| 40 | + /* Output fields and flags */ | |
| 41 | 41 | HMM_PFN_VALID = 1UL << (BITS_PER_LONG - 1), |
| 42 | 42 | HMM_PFN_WRITE = 1UL << (BITS_PER_LONG - 2), |
| 43 | 43 | HMM_PFN_ERROR = 1UL << (BITS_PER_LONG - 3), |
| 44 | + HMM_PFN_ORDER_SHIFT = (BITS_PER_LONG - 8), | |
| 44 | 45 | |
| 45 | 46 | /* Input flags */ |
| 46 | 47 | HMM_PFN_REQ_FAULT = HMM_PFN_VALID, |
| 47 | 48 | HMM_PFN_REQ_WRITE = HMM_PFN_WRITE, |
| 48 | 49 | |
| 49 | − HMM_PFN_FLAGS = HMM_PFN_VALID | HMM_PFN_WRITE | HMM_PFN_ERROR, | |
| 50 | + HMM_PFN_FLAGS = 0xFFUL << HMM_PFN_ORDER_SHIFT, | |
| 50 | 51 | }; |
| 51 | 52 | |
| 52 | 53 | /* |
| @@ -61,6 +62,25 @@ static inline struct page *hmm_pfn_to_page(unsigned long hmm_pfn) · 8 unmodified lines | ||
| 61 | 62 | return pfn_to_page(hmm_pfn & ~HMM_PFN_FLAGS); |
| 62 | 63 | } |
| 63 | 64 | |
| 65 | +/* | |
| 66 | + * hmm_pfn_to_map_order() - return the CPU mapping size order | |
| 67 | + * | |
| 68 | + * This is optionally useful to optimize processing of the pfn result | |
| 69 | + * array. It indicates that the page starts at the order aligned VA and is | |
| 70 | + * 1<<order bytes long. Every pfn within an high order page will have the | |
| 71 | + * same pfn flags, both access protections and the map_order. The caller must | |
| 72 | + * be careful with edge cases as the start and end VA of the given page may | |
| 73 | + * extend past the range used with hmm_range_fault(). | |
| 74 | + * | |
| 75 | + * This must be called under the caller 'user_lock' after a successful | |
| 76 | + * mmu_interval_read_begin(). The caller must have tested for HMM_PFN_VALID | |
| 77 | + * already. | |
| 78 | + */ | |
| 79 | +static inline unsigned int hmm_pfn_to_map_order(unsigned long hmm_pfn) | |
| 80 | +{ | |
| 81 | + return (hmm_pfn >> HMM_PFN_ORDER_SHIFT) & 0x1F; | |
| 82 | +} | |
| 83 | + | |
| 64 | 84 | /* |
| 65 | 85 | * struct hmm_range - track invalidation lock on virtual address range |
| 66 | 86 | * |
| @@ -180,6 +180,11 @@ static inline unsigned long migrate_pfn(unsigned long pfn) · 179 unmodified lines | ||
| 180 | 180 | return (pfn << MIGRATE_PFN_SHIFT) | MIGRATE_PFN_VALID; |
| 181 | 181 | } |
| 182 | 182 | |
| 183 | +enum migrate_vma_direction { | |
| 184 | + MIGRATE_VMA_SELECT_SYSTEM = 1 << 0, | |
| 185 | + MIGRATE_VMA_SELECT_DEVICE_PRIVATE = 1 << 1, | |
| 186 | +}; | |
| 187 | + | |
| 183 | 188 | struct migrate_vma { |
| 184 | 189 | struct vm_area_struct *vma; |
| 185 | 190 | /* |
| @@ -199,11 +204,14 @@ struct migrate_vma { · 13 unmodified lines | ||
| 199 | 204 | |
| 200 | 205 | /* |
| 201 | 206 | * Set to the owner value also stored in page->pgmap->owner for |
| 202 | − * migrating out of device private memory. If set only device | |
| 203 | − * private pages with this owner are migrated. If not set | |
| 204 | − * device private pages are not migrated at all. | |
| 207 | + * migrating out of device private memory. The flags also need to | |
| 208 | + * be set to MIGRATE_VMA_SELECT_DEVICE_PRIVATE. | |
| 209 | + * The caller should always set this field when using mmu notifier | |
| 210 | + * callbacks to avoid device MMU invalidations for device private | |
| 211 | + * pages that are not being migrated. | |
| 205 | 212 | */ |
| 206 | − void *src_owner; | |
| 213 | + void *pgmap_owner; | |
| 214 | + unsigned long flags; | |
| 207 | 215 | }; |
| 208 | 216 | |
| 209 | 217 | int migrate_vma_setup(struct migrate_vma *args); |
| @@ -38,6 +38,10 @@ struct mmu_interval_notifier; · 37 unmodified lines | ||
| 38 | 38 | * |
| 39 | 39 | * @MMU_NOTIFY_RELEASE: used during mmu_interval_notifier invalidate to signal |
| 40 | 40 | * that the mm refcount is zero and the range is no longer accessible. |
| 41 | + * | |
| 42 | + * @MMU_NOTIFY_MIGRATE: used during migrate_vma_collect() invalidate to signal | |
| 43 | + * a device driver to possibly ignore the invalidation if the | |
| 44 | + * migrate_pgmap_owner field matches the driver's device private pgmap owner. | |
| 41 | 45 | */ |
| 42 | 46 | enum mmu_notifier_event { |
| 43 | 47 | MMU_NOTIFY_UNMAP = 0, |
| @@ -46,6 +50,7 @@ enum mmu_notifier_event { · 2 unmodified lines | ||
| 46 | 50 | MMU_NOTIFY_PROTECTION_PAGE, |
| 47 | 51 | MMU_NOTIFY_SOFT_DIRTY, |
| 48 | 52 | MMU_NOTIFY_RELEASE, |
| 53 | + MMU_NOTIFY_MIGRATE, | |
| 49 | 54 | }; |
| 50 | 55 | |
| 51 | 56 | #define MMU_NOTIFIER_RANGE_BLOCKABLE (1 << 0) |
| @@ -264,6 +269,7 @@ struct mmu_notifier_range { · 212 unmodified lines | ||
| 264 | 269 | unsigned long end; |
| 265 | 270 | unsigned flags; |
| 266 | 271 | enum mmu_notifier_event event; |
| 272 | + void *migrate_pgmap_owner; | |
| 267 | 273 | }; |
| 268 | 274 | |
| 269 | 275 | static inline int mm_has_notifiers(struct mm_struct *mm) |