diff options
| -rw-r--r-- | arch/powerpc/configs/skiroot_defconfig | 1 | ||||
| -rw-r--r-- | arch/powerpc/mm/mmu_context_iommu.c | 97 | ||||
| -rw-r--r-- | arch/powerpc/platforms/Kconfig.cputype | 2 |
3 files changed, 60 insertions, 40 deletions
diff --git a/arch/powerpc/configs/skiroot_defconfig b/arch/powerpc/configs/skiroot_defconfig index 5ba131c30f6b..1bcd468ab422 100644 --- a/arch/powerpc/configs/skiroot_defconfig +++ b/arch/powerpc/configs/skiroot_defconfig | |||
| @@ -266,6 +266,7 @@ CONFIG_UDF_FS=m | |||
| 266 | CONFIG_MSDOS_FS=m | 266 | CONFIG_MSDOS_FS=m |
| 267 | CONFIG_VFAT_FS=m | 267 | CONFIG_VFAT_FS=m |
| 268 | CONFIG_PROC_KCORE=y | 268 | CONFIG_PROC_KCORE=y |
| 269 | CONFIG_HUGETLBFS=y | ||
| 269 | # CONFIG_MISC_FILESYSTEMS is not set | 270 | # CONFIG_MISC_FILESYSTEMS is not set |
| 270 | # CONFIG_NETWORK_FILESYSTEMS is not set | 271 | # CONFIG_NETWORK_FILESYSTEMS is not set |
| 271 | CONFIG_NLS=y | 272 | CONFIG_NLS=y |
diff --git a/arch/powerpc/mm/mmu_context_iommu.c b/arch/powerpc/mm/mmu_context_iommu.c index e7a9c4f6bfca..8330f135294f 100644 --- a/arch/powerpc/mm/mmu_context_iommu.c +++ b/arch/powerpc/mm/mmu_context_iommu.c | |||
| @@ -95,28 +95,15 @@ static long mm_iommu_do_alloc(struct mm_struct *mm, unsigned long ua, | |||
| 95 | unsigned long entries, unsigned long dev_hpa, | 95 | unsigned long entries, unsigned long dev_hpa, |
| 96 | struct mm_iommu_table_group_mem_t **pmem) | 96 | struct mm_iommu_table_group_mem_t **pmem) |
| 97 | { | 97 | { |
| 98 | struct mm_iommu_table_group_mem_t *mem; | 98 | struct mm_iommu_table_group_mem_t *mem, *mem2; |
| 99 | long i, ret, locked_entries = 0; | 99 | long i, ret, locked_entries = 0, pinned = 0; |
| 100 | unsigned int pageshift; | 100 | unsigned int pageshift; |
| 101 | 101 | unsigned long entry, chunk; | |
| 102 | mutex_lock(&mem_list_mutex); | ||
| 103 | |||
| 104 | list_for_each_entry_rcu(mem, &mm->context.iommu_group_mem_list, | ||
| 105 | next) { | ||
| 106 | /* Overlap? */ | ||
| 107 | if ((mem->ua < (ua + (entries << PAGE_SHIFT))) && | ||
| 108 | (ua < (mem->ua + | ||
| 109 | (mem->entries << PAGE_SHIFT)))) { | ||
| 110 | ret = -EINVAL; | ||
| 111 | goto unlock_exit; | ||
| 112 | } | ||
| 113 | |||
| 114 | } | ||
| 115 | 102 | ||
| 116 | if (dev_hpa == MM_IOMMU_TABLE_INVALID_HPA) { | 103 | if (dev_hpa == MM_IOMMU_TABLE_INVALID_HPA) { |
| 117 | ret = mm_iommu_adjust_locked_vm(mm, entries, true); | 104 | ret = mm_iommu_adjust_locked_vm(mm, entries, true); |
| 118 | if (ret) | 105 | if (ret) |
| 119 | goto unlock_exit; | 106 | return ret; |
| 120 | 107 | ||
| 121 | locked_entries = entries; | 108 | locked_entries = entries; |
| 122 | } | 109 | } |
| @@ -148,17 +135,27 @@ static long mm_iommu_do_alloc(struct mm_struct *mm, unsigned long ua, | |||
| 148 | } | 135 | } |
| 149 | 136 | ||
| 150 | down_read(&mm->mmap_sem); | 137 | down_read(&mm->mmap_sem); |
| 151 | ret = get_user_pages_longterm(ua, entries, FOLL_WRITE, mem->hpages, NULL); | 138 | chunk = (1UL << (PAGE_SHIFT + MAX_ORDER - 1)) / |
| 139 | sizeof(struct vm_area_struct *); | ||
| 140 | chunk = min(chunk, entries); | ||
| 141 | for (entry = 0; entry < entries; entry += chunk) { | ||
| 142 | unsigned long n = min(entries - entry, chunk); | ||
| 143 | |||
| 144 | ret = get_user_pages_longterm(ua + (entry << PAGE_SHIFT), n, | ||
| 145 | FOLL_WRITE, mem->hpages + entry, NULL); | ||
| 146 | if (ret == n) { | ||
| 147 | pinned += n; | ||
| 148 | continue; | ||
| 149 | } | ||
| 150 | if (ret > 0) | ||
| 151 | pinned += ret; | ||
| 152 | break; | ||
| 153 | } | ||
| 152 | up_read(&mm->mmap_sem); | 154 | up_read(&mm->mmap_sem); |
| 153 | if (ret != entries) { | 155 | if (pinned != entries) { |
| 154 | /* free the reference taken */ | 156 | if (!ret) |
| 155 | for (i = 0; i < ret; i++) | 157 | ret = -EFAULT; |
| 156 | put_page(mem->hpages[i]); | 158 | goto free_exit; |
| 157 | |||
| 158 | vfree(mem->hpas); | ||
| 159 | kfree(mem); | ||
| 160 | ret = -EFAULT; | ||
| 161 | goto unlock_exit; | ||
| 162 | } | 159 | } |
| 163 | 160 | ||
| 164 | pageshift = PAGE_SHIFT; | 161 | pageshift = PAGE_SHIFT; |
| @@ -183,21 +180,43 @@ static long mm_iommu_do_alloc(struct mm_struct *mm, unsigned long ua, | |||
| 183 | } | 180 | } |
| 184 | 181 | ||
| 185 | good_exit: | 182 | good_exit: |
| 186 | ret = 0; | ||
| 187 | atomic64_set(&mem->mapped, 1); | 183 | atomic64_set(&mem->mapped, 1); |
| 188 | mem->used = 1; | 184 | mem->used = 1; |
| 189 | mem->ua = ua; | 185 | mem->ua = ua; |
| 190 | mem->entries = entries; | 186 | mem->entries = entries; |
| 191 | *pmem = mem; | ||
| 192 | 187 | ||
| 193 | list_add_rcu(&mem->next, &mm->context.iommu_group_mem_list); | 188 | mutex_lock(&mem_list_mutex); |
| 194 | 189 | ||
| 195 | unlock_exit: | 190 | list_for_each_entry_rcu(mem2, &mm->context.iommu_group_mem_list, next) { |
| 196 | if (locked_entries && ret) | 191 | /* Overlap? */ |
| 197 | mm_iommu_adjust_locked_vm(mm, locked_entries, false); | 192 | if ((mem2->ua < (ua + (entries << PAGE_SHIFT))) && |
| 193 | (ua < (mem2->ua + | ||
| 194 | (mem2->entries << PAGE_SHIFT)))) { | ||
| 195 | ret = -EINVAL; | ||
| 196 | mutex_unlock(&mem_list_mutex); | ||
| 197 | goto free_exit; | ||
| 198 | } | ||
| 199 | } | ||
| 200 | |||
| 201 | list_add_rcu(&mem->next, &mm->context.iommu_group_mem_list); | ||
| 198 | 202 | ||
| 199 | mutex_unlock(&mem_list_mutex); | 203 | mutex_unlock(&mem_list_mutex); |
| 200 | 204 | ||
| 205 | *pmem = mem; | ||
| 206 | |||
| 207 | return 0; | ||
| 208 | |||
| 209 | free_exit: | ||
| 210 | /* free the reference taken */ | ||
| 211 | for (i = 0; i < pinned; i++) | ||
| 212 | put_page(mem->hpages[i]); | ||
| 213 | |||
| 214 | vfree(mem->hpas); | ||
| 215 | kfree(mem); | ||
| 216 | |||
| 217 | unlock_exit: | ||
| 218 | mm_iommu_adjust_locked_vm(mm, locked_entries, false); | ||
| 219 | |||
| 201 | return ret; | 220 | return ret; |
| 202 | } | 221 | } |
| 203 | 222 | ||
| @@ -266,7 +285,7 @@ static void mm_iommu_release(struct mm_iommu_table_group_mem_t *mem) | |||
| 266 | long mm_iommu_put(struct mm_struct *mm, struct mm_iommu_table_group_mem_t *mem) | 285 | long mm_iommu_put(struct mm_struct *mm, struct mm_iommu_table_group_mem_t *mem) |
| 267 | { | 286 | { |
| 268 | long ret = 0; | 287 | long ret = 0; |
| 269 | unsigned long entries, dev_hpa; | 288 | unsigned long unlock_entries = 0; |
| 270 | 289 | ||
| 271 | mutex_lock(&mem_list_mutex); | 290 | mutex_lock(&mem_list_mutex); |
| 272 | 291 | ||
| @@ -287,17 +306,17 @@ long mm_iommu_put(struct mm_struct *mm, struct mm_iommu_table_group_mem_t *mem) | |||
| 287 | goto unlock_exit; | 306 | goto unlock_exit; |
| 288 | } | 307 | } |
| 289 | 308 | ||
| 309 | if (mem->dev_hpa == MM_IOMMU_TABLE_INVALID_HPA) | ||
| 310 | unlock_entries = mem->entries; | ||
| 311 | |||
| 290 | /* @mapped became 0 so now mappings are disabled, release the region */ | 312 | /* @mapped became 0 so now mappings are disabled, release the region */ |
| 291 | entries = mem->entries; | ||
| 292 | dev_hpa = mem->dev_hpa; | ||
| 293 | mm_iommu_release(mem); | 313 | mm_iommu_release(mem); |
| 294 | 314 | ||
| 295 | if (dev_hpa == MM_IOMMU_TABLE_INVALID_HPA) | ||
| 296 | mm_iommu_adjust_locked_vm(mm, entries, false); | ||
| 297 | |||
| 298 | unlock_exit: | 315 | unlock_exit: |
| 299 | mutex_unlock(&mem_list_mutex); | 316 | mutex_unlock(&mem_list_mutex); |
| 300 | 317 | ||
| 318 | mm_iommu_adjust_locked_vm(mm, unlock_entries, false); | ||
| 319 | |||
| 301 | return ret; | 320 | return ret; |
| 302 | } | 321 | } |
| 303 | EXPORT_SYMBOL_GPL(mm_iommu_put); | 322 | EXPORT_SYMBOL_GPL(mm_iommu_put); |
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index 842b2c7e156a..50cd09b4e05d 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype | |||
| @@ -324,7 +324,7 @@ config ARCH_ENABLE_SPLIT_PMD_PTLOCK | |||
| 324 | 324 | ||
| 325 | config PPC_RADIX_MMU | 325 | config PPC_RADIX_MMU |
| 326 | bool "Radix MMU Support" | 326 | bool "Radix MMU Support" |
| 327 | depends on PPC_BOOK3S_64 | 327 | depends on PPC_BOOK3S_64 && HUGETLB_PAGE |
| 328 | select ARCH_HAS_GIGANTIC_PAGE if (MEMORY_ISOLATION && COMPACTION) || CMA | 328 | select ARCH_HAS_GIGANTIC_PAGE if (MEMORY_ISOLATION && COMPACTION) || CMA |
| 329 | default y | 329 | default y |
| 330 | help | 330 | help |
