pgtable.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright IBM Corp. 2007, 2011
  4. * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
  5. */
  6. #include <linux/cpufeature.h>
  7. #include <linux/export.h>
  8. #include <linux/sched.h>
  9. #include <linux/kernel.h>
  10. #include <linux/errno.h>
  11. #include <linux/gfp.h>
  12. #include <linux/mm.h>
  13. #include <linux/swap.h>
  14. #include <linux/smp.h>
  15. #include <linux/spinlock.h>
  16. #include <linux/rcupdate.h>
  17. #include <linux/slab.h>
  18. #include <linux/leafops.h>
  19. #include <linux/sysctl.h>
  20. #include <linux/ksm.h>
  21. #include <linux/mman.h>
  22. #include <asm/tlbflush.h>
  23. #include <asm/mmu_context.h>
  24. #include <asm/page-states.h>
  25. #include <asm/machine.h>
  26. pgprot_t pgprot_writecombine(pgprot_t prot)
  27. {
  28. /*
  29. * mio_wb_bit_mask may be set on a different CPU, but it is only set
  30. * once at init and only read afterwards.
  31. */
  32. return __pgprot(pgprot_val(prot) | mio_wb_bit_mask);
  33. }
  34. EXPORT_SYMBOL_GPL(pgprot_writecombine);
  35. static inline void ptep_ipte_local(struct mm_struct *mm, unsigned long addr,
  36. pte_t *ptep, int nodat)
  37. {
  38. unsigned long opt, asce;
  39. if (machine_has_tlb_guest()) {
  40. opt = 0;
  41. asce = READ_ONCE(mm->context.gmap_asce);
  42. if (asce == 0UL || nodat)
  43. opt |= IPTE_NODAT;
  44. if (asce != -1UL) {
  45. asce = asce ? : mm->context.asce;
  46. opt |= IPTE_GUEST_ASCE;
  47. }
  48. __ptep_ipte(addr, ptep, opt, asce, IPTE_LOCAL);
  49. } else {
  50. __ptep_ipte(addr, ptep, 0, 0, IPTE_LOCAL);
  51. }
  52. }
  53. static inline void ptep_ipte_global(struct mm_struct *mm, unsigned long addr,
  54. pte_t *ptep, int nodat)
  55. {
  56. unsigned long opt, asce;
  57. if (machine_has_tlb_guest()) {
  58. opt = 0;
  59. asce = READ_ONCE(mm->context.gmap_asce);
  60. if (asce == 0UL || nodat)
  61. opt |= IPTE_NODAT;
  62. if (asce != -1UL) {
  63. asce = asce ? : mm->context.asce;
  64. opt |= IPTE_GUEST_ASCE;
  65. }
  66. __ptep_ipte(addr, ptep, opt, asce, IPTE_GLOBAL);
  67. } else {
  68. __ptep_ipte(addr, ptep, 0, 0, IPTE_GLOBAL);
  69. }
  70. }
  71. static inline pte_t ptep_flush_direct(struct mm_struct *mm,
  72. unsigned long addr, pte_t *ptep,
  73. int nodat)
  74. {
  75. pte_t old;
  76. old = *ptep;
  77. if (unlikely(pte_val(old) & _PAGE_INVALID))
  78. return old;
  79. atomic_inc(&mm->context.flush_count);
  80. if (cpu_has_tlb_lc() &&
  81. cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id())))
  82. ptep_ipte_local(mm, addr, ptep, nodat);
  83. else
  84. ptep_ipte_global(mm, addr, ptep, nodat);
  85. atomic_dec(&mm->context.flush_count);
  86. return old;
  87. }
  88. static inline pte_t ptep_flush_lazy(struct mm_struct *mm,
  89. unsigned long addr, pte_t *ptep,
  90. int nodat)
  91. {
  92. pte_t old;
  93. old = *ptep;
  94. if (unlikely(pte_val(old) & _PAGE_INVALID))
  95. return old;
  96. atomic_inc(&mm->context.flush_count);
  97. if (cpumask_equal(&mm->context.cpu_attach_mask,
  98. cpumask_of(smp_processor_id()))) {
  99. set_pte(ptep, set_pte_bit(*ptep, __pgprot(_PAGE_INVALID)));
  100. mm->context.flush_mm = 1;
  101. } else
  102. ptep_ipte_global(mm, addr, ptep, nodat);
  103. atomic_dec(&mm->context.flush_count);
  104. return old;
  105. }
  106. pte_t ptep_xchg_direct(struct mm_struct *mm, unsigned long addr,
  107. pte_t *ptep, pte_t new)
  108. {
  109. pte_t old;
  110. preempt_disable();
  111. old = ptep_flush_direct(mm, addr, ptep, 1);
  112. set_pte(ptep, new);
  113. preempt_enable();
  114. return old;
  115. }
  116. EXPORT_SYMBOL(ptep_xchg_direct);
  117. /*
  118. * Caller must check that new PTE only differs in _PAGE_PROTECT HW bit, so that
  119. * RDP can be used instead of IPTE. See also comments at pte_allow_rdp().
  120. */
  121. void ptep_reset_dat_prot(struct mm_struct *mm, unsigned long addr, pte_t *ptep,
  122. pte_t new)
  123. {
  124. preempt_disable();
  125. atomic_inc(&mm->context.flush_count);
  126. if (cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id())))
  127. __ptep_rdp(addr, ptep, 1);
  128. else
  129. __ptep_rdp(addr, ptep, 0);
  130. /*
  131. * PTE is not invalidated by RDP, only _PAGE_PROTECT is cleared. That
  132. * means it is still valid and active, and must not be changed according
  133. * to the architecture. But writing a new value that only differs in SW
  134. * bits is allowed.
  135. */
  136. set_pte(ptep, new);
  137. atomic_dec(&mm->context.flush_count);
  138. preempt_enable();
  139. }
  140. EXPORT_SYMBOL(ptep_reset_dat_prot);
  141. pte_t ptep_xchg_lazy(struct mm_struct *mm, unsigned long addr,
  142. pte_t *ptep, pte_t new)
  143. {
  144. pte_t old;
  145. preempt_disable();
  146. old = ptep_flush_lazy(mm, addr, ptep, 1);
  147. set_pte(ptep, new);
  148. preempt_enable();
  149. return old;
  150. }
  151. EXPORT_SYMBOL(ptep_xchg_lazy);
  152. pte_t ptep_modify_prot_start(struct vm_area_struct *vma, unsigned long addr,
  153. pte_t *ptep)
  154. {
  155. return ptep_flush_lazy(vma->vm_mm, addr, ptep, 1);
  156. }
  157. void ptep_modify_prot_commit(struct vm_area_struct *vma, unsigned long addr,
  158. pte_t *ptep, pte_t old_pte, pte_t pte)
  159. {
  160. set_pte(ptep, pte);
  161. }
  162. static inline void pmdp_idte_local(struct mm_struct *mm,
  163. unsigned long addr, pmd_t *pmdp)
  164. {
  165. if (machine_has_tlb_guest())
  166. __pmdp_idte(addr, pmdp, IDTE_NODAT | IDTE_GUEST_ASCE, mm->context.asce, IDTE_LOCAL);
  167. else
  168. __pmdp_idte(addr, pmdp, 0, 0, IDTE_LOCAL);
  169. }
  170. static inline void pmdp_idte_global(struct mm_struct *mm,
  171. unsigned long addr, pmd_t *pmdp)
  172. {
  173. if (machine_has_tlb_guest()) {
  174. __pmdp_idte(addr, pmdp, IDTE_NODAT | IDTE_GUEST_ASCE,
  175. mm->context.asce, IDTE_GLOBAL);
  176. } else {
  177. __pmdp_idte(addr, pmdp, 0, 0, IDTE_GLOBAL);
  178. }
  179. }
  180. static inline pmd_t pmdp_flush_direct(struct mm_struct *mm,
  181. unsigned long addr, pmd_t *pmdp)
  182. {
  183. pmd_t old;
  184. old = *pmdp;
  185. if (pmd_val(old) & _SEGMENT_ENTRY_INVALID)
  186. return old;
  187. atomic_inc(&mm->context.flush_count);
  188. if (cpu_has_tlb_lc() &&
  189. cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id())))
  190. pmdp_idte_local(mm, addr, pmdp);
  191. else
  192. pmdp_idte_global(mm, addr, pmdp);
  193. atomic_dec(&mm->context.flush_count);
  194. return old;
  195. }
  196. static inline pmd_t pmdp_flush_lazy(struct mm_struct *mm,
  197. unsigned long addr, pmd_t *pmdp)
  198. {
  199. pmd_t old;
  200. old = *pmdp;
  201. if (pmd_val(old) & _SEGMENT_ENTRY_INVALID)
  202. return old;
  203. atomic_inc(&mm->context.flush_count);
  204. if (cpumask_equal(&mm->context.cpu_attach_mask,
  205. cpumask_of(smp_processor_id()))) {
  206. set_pmd(pmdp, set_pmd_bit(*pmdp, __pgprot(_SEGMENT_ENTRY_INVALID)));
  207. mm->context.flush_mm = 1;
  208. } else {
  209. pmdp_idte_global(mm, addr, pmdp);
  210. }
  211. atomic_dec(&mm->context.flush_count);
  212. return old;
  213. }
  214. pmd_t pmdp_xchg_direct(struct mm_struct *mm, unsigned long addr,
  215. pmd_t *pmdp, pmd_t new)
  216. {
  217. pmd_t old;
  218. preempt_disable();
  219. old = pmdp_flush_direct(mm, addr, pmdp);
  220. set_pmd(pmdp, new);
  221. preempt_enable();
  222. return old;
  223. }
  224. EXPORT_SYMBOL(pmdp_xchg_direct);
  225. pmd_t pmdp_xchg_lazy(struct mm_struct *mm, unsigned long addr,
  226. pmd_t *pmdp, pmd_t new)
  227. {
  228. pmd_t old;
  229. preempt_disable();
  230. old = pmdp_flush_lazy(mm, addr, pmdp);
  231. set_pmd(pmdp, new);
  232. preempt_enable();
  233. return old;
  234. }
  235. EXPORT_SYMBOL(pmdp_xchg_lazy);
  236. static inline void pudp_idte_local(struct mm_struct *mm,
  237. unsigned long addr, pud_t *pudp)
  238. {
  239. if (machine_has_tlb_guest())
  240. __pudp_idte(addr, pudp, IDTE_NODAT | IDTE_GUEST_ASCE,
  241. mm->context.asce, IDTE_LOCAL);
  242. else
  243. __pudp_idte(addr, pudp, 0, 0, IDTE_LOCAL);
  244. }
  245. static inline void pudp_idte_global(struct mm_struct *mm,
  246. unsigned long addr, pud_t *pudp)
  247. {
  248. if (machine_has_tlb_guest())
  249. __pudp_idte(addr, pudp, IDTE_NODAT | IDTE_GUEST_ASCE,
  250. mm->context.asce, IDTE_GLOBAL);
  251. else
  252. __pudp_idte(addr, pudp, 0, 0, IDTE_GLOBAL);
  253. }
  254. static inline pud_t pudp_flush_direct(struct mm_struct *mm,
  255. unsigned long addr, pud_t *pudp)
  256. {
  257. pud_t old;
  258. old = *pudp;
  259. if (pud_val(old) & _REGION_ENTRY_INVALID)
  260. return old;
  261. atomic_inc(&mm->context.flush_count);
  262. if (cpu_has_tlb_lc() &&
  263. cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id())))
  264. pudp_idte_local(mm, addr, pudp);
  265. else
  266. pudp_idte_global(mm, addr, pudp);
  267. atomic_dec(&mm->context.flush_count);
  268. return old;
  269. }
  270. pud_t pudp_xchg_direct(struct mm_struct *mm, unsigned long addr,
  271. pud_t *pudp, pud_t new)
  272. {
  273. pud_t old;
  274. preempt_disable();
  275. old = pudp_flush_direct(mm, addr, pudp);
  276. set_pud(pudp, new);
  277. preempt_enable();
  278. return old;
  279. }
  280. EXPORT_SYMBOL(pudp_xchg_direct);
  281. #ifdef CONFIG_TRANSPARENT_HUGEPAGE
  282. void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,
  283. pgtable_t pgtable)
  284. {
  285. struct list_head *lh = (struct list_head *) pgtable;
  286. assert_spin_locked(pmd_lockptr(mm, pmdp));
  287. /* FIFO */
  288. if (!pmd_huge_pte(mm, pmdp))
  289. INIT_LIST_HEAD(lh);
  290. else
  291. list_add(lh, (struct list_head *) pmd_huge_pte(mm, pmdp));
  292. pmd_huge_pte(mm, pmdp) = pgtable;
  293. }
  294. pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp)
  295. {
  296. struct list_head *lh;
  297. pgtable_t pgtable;
  298. pte_t *ptep;
  299. assert_spin_locked(pmd_lockptr(mm, pmdp));
  300. /* FIFO */
  301. pgtable = pmd_huge_pte(mm, pmdp);
  302. lh = (struct list_head *) pgtable;
  303. if (list_empty(lh))
  304. pmd_huge_pte(mm, pmdp) = NULL;
  305. else {
  306. pmd_huge_pte(mm, pmdp) = (pgtable_t) lh->next;
  307. list_del(lh);
  308. }
  309. ptep = (pte_t *) pgtable;
  310. set_pte(ptep, __pte(_PAGE_INVALID));
  311. ptep++;
  312. set_pte(ptep, __pte(_PAGE_INVALID));
  313. return pgtable;
  314. }
  315. #endif /* CONFIG_TRANSPARENT_HUGEPAGE */