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 | * will fail. Must be combined with HMM_PFN_REQ_FAULT. | 37 | * will fail. Must be combined with HMM_PFN_REQ_FAULT. |
| 38 | */ | 38 | */ |
| 39 | enum hmm_pfn_flags { | 39 | enum hmm_pfn_flags { |
| 40 | /* Output flags */ | 40 | /* Output fields and flags */ |
| 41 | HMM_PFN_VALID = 1UL << (BITS_PER_LONG - 1), | 41 | HMM_PFN_VALID = 1UL << (BITS_PER_LONG - 1), |
| 42 | HMM_PFN_WRITE = 1UL << (BITS_PER_LONG - 2), | 42 | HMM_PFN_WRITE = 1UL << (BITS_PER_LONG - 2), |
| 43 | HMM_PFN_ERROR = 1UL << (BITS_PER_LONG - 3), | 43 | HMM_PFN_ERROR = 1UL << (BITS_PER_LONG - 3), |
| 44 | HMM_PFN_ORDER_SHIFT = (BITS_PER_LONG - 8), | ||
| 44 | 45 | ||
| 45 | /* Input flags */ | 46 | /* Input flags */ |
| 46 | HMM_PFN_REQ_FAULT = HMM_PFN_VALID, | 47 | HMM_PFN_REQ_FAULT = HMM_PFN_VALID, |
| 47 | HMM_PFN_REQ_WRITE = HMM_PFN_WRITE, | 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 | return pfn_to_page(hmm_pfn & ~HMM_PFN_FLAGS); | 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 | * struct hmm_range - track invalidation lock on virtual address range | 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 | return (pfn << MIGRATE_PFN_SHIFT) | MIGRATE_PFN_VALID; | 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 | struct migrate_vma { | 188 | struct migrate_vma { |
| 184 | struct vm_area_struct *vma; | 189 | struct vm_area_struct *vma; |
| 185 | /* | 190 | /* |
| @@ -199,11 +204,14 @@ struct migrate_vma { · 13 unmodified lines | |||
| 199 | 204 | ||
| 200 | /* | 205 | /* |
| 201 | * Set to the owner value also stored in page->pgmap->owner for | 206 | * Set to the owner value also stored in page->pgmap->owner for |
| 202 | * migrating out of device private memory. If set only device | 207 | * migrating out of device private memory. The flags also need to |
| 203 | * private pages with this owner are migrated. If not set | 208 | * be set to MIGRATE_VMA_SELECT_DEVICE_PRIVATE. |
| 204 | * device private pages are not migrated at all. | 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 | int migrate_vma_setup(struct migrate_vma *args); | 217 | int migrate_vma_setup(struct migrate_vma *args); |
| @@ -38,6 +38,10 @@ struct mmu_interval_notifier; · 37 unmodified lines | |||
| 38 | * | 38 | * |
| 39 | * @MMU_NOTIFY_RELEASE: used during mmu_interval_notifier invalidate to signal | 39 | * @MMU_NOTIFY_RELEASE: used during mmu_interval_notifier invalidate to signal |
| 40 | * that the mm refcount is zero and the range is no longer accessible. | 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 | enum mmu_notifier_event { | 46 | enum mmu_notifier_event { |
| 43 | MMU_NOTIFY_UNMAP = 0, | 47 | MMU_NOTIFY_UNMAP = 0, |
| @@ -46,6 +50,7 @@ enum mmu_notifier_event { · 2 unmodified lines | |||
| 46 | MMU_NOTIFY_PROTECTION_PAGE, | 50 | MMU_NOTIFY_PROTECTION_PAGE, |
| 47 | MMU_NOTIFY_SOFT_DIRTY, | 51 | MMU_NOTIFY_SOFT_DIRTY, |
| 48 | MMU_NOTIFY_RELEASE, | 52 | MMU_NOTIFY_RELEASE, |
| 53 | MMU_NOTIFY_MIGRATE, | ||
| 49 | }; | 54 | }; |
| 50 | 55 | ||
| 51 | #define MMU_NOTIFIER_RANGE_BLOCKABLE (1 << 0) | 56 | #define MMU_NOTIFIER_RANGE_BLOCKABLE (1 << 0) |
| @@ -264,6 +269,7 @@ struct mmu_notifier_range { · 212 unmodified lines | |||
| 264 | unsigned long end; | 269 | unsigned long end; |
| 265 | unsigned flags; | 270 | unsigned flags; |
| 266 | enum mmu_notifier_event event; | 271 | enum mmu_notifier_event event; |
| 272 | void *migrate_pgmap_owner; | ||
| 267 | }; | 273 | }; |
| 268 | 274 | ||
| 269 | static inline int mm_has_notifiers(struct mm_struct *mm) | 275 | static inline int mm_has_notifiers(struct mm_struct *mm) |