Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[S390] refactor page table functions for better pgste support

Rework the architecture page table functions to access the bits in the
page table extension array (pgste). There are a number of changes:
1) Fix missing pgste update if the attach_count for the mm is <= 1.
2) For every operation that affects the invalid bit in the pte or the
rcp byte in the pgste the pcl lock needs to be acquired. The function
pgste_get_lock gets the pcl lock and returns the current pgste value
for a pte pointer. The function pgste_set_unlock stores the pgste
and releases the lock. Between these two calls the bits in the pgste
can be shuffled.
3) Define two software bits in the pte _PAGE_SWR and _PAGE_SWC to avoid
calling SetPageDirty and SetPageReferenced from pgtable.h. If the
host reference backup bit or the host change backup bit has been
set the dirty/referenced state is transfered to the pte. The common
code will pick up the state from the pte.
4) Add ptep_modify_prot_start and ptep_modify_prot_commit for mprotect.
5) Remove pgd_populate_kernel, pud_populate_kernel, pmd_populate_kernel
pgd_clear_kernel, pud_clear_kernel, pmd_clear_kernel and ptep_invalidate.
6) Rename kvm_s390_test_and_clear_page_dirty to
ptep_test_and_clear_user_dirty and add ptep_test_and_clear_user_young.
7) Define mm_exclusive() and mm_has_pgste() helper to improve readability.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

+333 -235
+4 -2
arch/s390/include/asm/mmu.h
··· 9 9 unsigned long asce_bits; 10 10 unsigned long asce_limit; 11 11 unsigned long vdso_base; 12 - int has_pgste; /* The mmu context has extended page tables */ 13 - int alloc_pgste; /* cloned contexts will have extended page tables */ 12 + /* Cloned contexts will be created with extended page tables. */ 13 + unsigned int alloc_pgste:1; 14 + /* The mmu context has extended page tables. */ 15 + unsigned int has_pgste:1; 14 16 } mm_context_t; 15 17 16 18 #define INIT_MM_CONTEXT(name) \
+4
arch/s390/include/asm/page.h
··· 90 90 */ 91 91 92 92 typedef struct { unsigned long pgprot; } pgprot_t; 93 + typedef struct { unsigned long pgste; } pgste_t; 93 94 typedef struct { unsigned long pte; } pte_t; 94 95 typedef struct { unsigned long pmd; } pmd_t; 95 96 typedef struct { unsigned long pud; } pud_t; ··· 98 97 typedef pte_t *pgtable_t; 99 98 100 99 #define pgprot_val(x) ((x).pgprot) 100 + #define pgste_val(x) ((x).pgste) 101 101 #define pte_val(x) ((x).pte) 102 102 #define pmd_val(x) ((x).pmd) 103 103 #define pud_val(x) ((x).pud) 104 104 #define pgd_val(x) ((x).pgd) 105 105 106 + #define __pgste(x) ((pgste_t) { (x) } ) 106 107 #define __pte(x) ((pte_t) { (x) } ) 107 108 #define __pmd(x) ((pmd_t) { (x) } ) 109 + #define __pud(x) ((pud_t) { (x) } ) 108 110 #define __pgd(x) ((pgd_t) { (x) } ) 109 111 #define __pgprot(x) ((pgprot_t) { (x) } ) 110 112
+5 -24
arch/s390/include/asm/pgalloc.h
··· 65 65 #define pmd_free(mm, x) do { } while (0) 66 66 67 67 #define pgd_populate(mm, pgd, pud) BUG() 68 - #define pgd_populate_kernel(mm, pgd, pud) BUG() 69 - 70 68 #define pud_populate(mm, pud, pmd) BUG() 71 - #define pud_populate_kernel(mm, pud, pmd) BUG() 72 69 73 70 #else /* __s390x__ */ 74 71 ··· 99 102 } 100 103 #define pmd_free(mm, pmd) crst_table_free(mm, (unsigned long *) pmd) 101 104 102 - static inline void pgd_populate_kernel(struct mm_struct *mm, 103 - pgd_t *pgd, pud_t *pud) 105 + static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud) 104 106 { 105 107 pgd_val(*pgd) = _REGION2_ENTRY | __pa(pud); 106 108 } 107 109 108 - static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud) 109 - { 110 - pgd_populate_kernel(mm, pgd, pud); 111 - } 112 - 113 - static inline void pud_populate_kernel(struct mm_struct *mm, 114 - pud_t *pud, pmd_t *pmd) 115 - { 116 - pud_val(*pud) = _REGION3_ENTRY | __pa(pmd); 117 - } 118 - 119 110 static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) 120 111 { 121 - pud_populate_kernel(mm, pud, pmd); 112 + pud_val(*pud) = _REGION3_ENTRY | __pa(pmd); 122 113 } 123 114 124 115 #endif /* __s390x__ */ ··· 119 134 } 120 135 #define pgd_free(mm, pgd) crst_table_free(mm, (unsigned long *) pgd) 121 136 122 - static inline void pmd_populate_kernel(struct mm_struct *mm, 123 - pmd_t *pmd, pte_t *pte) 137 + static inline void pmd_populate(struct mm_struct *mm, 138 + pmd_t *pmd, pgtable_t pte) 124 139 { 125 140 pmd_val(*pmd) = _SEGMENT_ENTRY + __pa(pte); 126 141 } 127 142 128 - static inline void pmd_populate(struct mm_struct *mm, 129 - pmd_t *pmd, pgtable_t pte) 130 - { 131 - pmd_populate_kernel(mm, pmd, pte); 132 - } 143 + #define pmd_populate_kernel(mm, pmd, pte) pmd_populate(mm, pmd, pte) 133 144 134 145 #define pmd_pgtable(pmd) \ 135 146 (pgtable_t)(pmd_val(pmd) & -sizeof(pte_t)*PTRS_PER_PTE)
+310 -200
arch/s390/include/asm/pgtable.h
··· 31 31 #ifndef __ASSEMBLY__ 32 32 #include <linux/sched.h> 33 33 #include <linux/mm_types.h> 34 - #include <asm/bitops.h> 35 34 #include <asm/bug.h> 36 - #include <asm/processor.h> 35 + #include <asm/page.h> 37 36 38 37 extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096))); 39 38 extern void paging_init(void); ··· 242 243 /* Software bits in the page table entry */ 243 244 #define _PAGE_SWT 0x001 /* SW pte type bit t */ 244 245 #define _PAGE_SWX 0x002 /* SW pte type bit x */ 245 - #define _PAGE_SPECIAL 0x004 /* SW associated with special page */ 246 + #define _PAGE_SWC 0x004 /* SW pte changed bit (for KVM) */ 247 + #define _PAGE_SWR 0x008 /* SW pte referenced bit (for KVM) */ 248 + #define _PAGE_SPECIAL 0x010 /* SW associated with special page */ 246 249 #define __HAVE_ARCH_PTE_SPECIAL 247 250 248 251 /* Set of bits not changed in pte_modify */ 249 - #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_SPECIAL) 252 + #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_SPECIAL | _PAGE_SWC | _PAGE_SWR) 250 253 251 254 /* Six different types of pages. */ 252 255 #define _PAGE_TYPE_EMPTY 0x400 ··· 294 293 */ 295 294 296 295 /* Page status table bits for virtualization */ 297 - #define RCP_PCL_BIT 55 298 - #define RCP_HR_BIT 54 299 - #define RCP_HC_BIT 53 300 - #define RCP_GR_BIT 50 301 - #define RCP_GC_BIT 49 296 + #define RCP_ACC_BITS 0xf000000000000000UL 297 + #define RCP_FP_BIT 0x0800000000000000UL 298 + #define RCP_PCL_BIT 0x0080000000000000UL 299 + #define RCP_HR_BIT 0x0040000000000000UL 300 + #define RCP_HC_BIT 0x0020000000000000UL 301 + #define RCP_GR_BIT 0x0004000000000000UL 302 + #define RCP_GC_BIT 0x0002000000000000UL 302 303 303 - /* User dirty bit for KVM's migration feature */ 304 - #define KVM_UD_BIT 47 304 + /* User dirty / referenced bit for KVM's migration feature */ 305 + #define KVM_UR_BIT 0x0000800000000000UL 306 + #define KVM_UC_BIT 0x0000400000000000UL 305 307 306 308 #ifndef __s390x__ 307 309 ··· 411 407 #define __S110 PAGE_RW 412 408 #define __S111 PAGE_RW 413 409 414 - /* 415 - * Certain architectures need to do special things when PTEs 416 - * within a page table are directly modified. Thus, the following 417 - * hook is made available. 418 - */ 419 - static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, 420 - pte_t *ptep, pte_t entry) 410 + static inline int mm_exclusive(struct mm_struct *mm) 421 411 { 422 - *ptep = entry; 412 + return likely(mm == current->active_mm && 413 + atomic_read(&mm->context.attach_count) <= 1); 423 414 } 424 415 416 + static inline int mm_has_pgste(struct mm_struct *mm) 417 + { 418 + #ifdef CONFIG_PGSTE 419 + if (unlikely(mm->context.has_pgste)) 420 + return 1; 421 + #endif 422 + return 0; 423 + } 425 424 /* 426 425 * pgd/pmd/pte query functions 427 426 */ ··· 537 530 } 538 531 539 532 #define __HAVE_ARCH_PTE_SAME 540 - #define pte_same(a,b) (pte_val(a) == pte_val(b)) 541 - 542 - static inline void rcp_lock(pte_t *ptep) 533 + static inline int pte_same(pte_t a, pte_t b) 543 534 { 544 - #ifdef CONFIG_PGSTE 545 - unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE); 546 - preempt_disable(); 547 - while (test_and_set_bit(RCP_PCL_BIT, pgste)) 548 - ; 549 - #endif 535 + return pte_val(a) == pte_val(b); 550 536 } 551 537 552 - static inline void rcp_unlock(pte_t *ptep) 538 + static inline pgste_t pgste_get_lock(pte_t *ptep) 539 + { 540 + unsigned long new = 0; 541 + #ifdef CONFIG_PGSTE 542 + unsigned long old; 543 + 544 + preempt_disable(); 545 + asm( 546 + " lg %0,%2\n" 547 + "0: lgr %1,%0\n" 548 + " nihh %0,0xff7f\n" /* clear RCP_PCL_BIT in old */ 549 + " oihh %1,0x0080\n" /* set RCP_PCL_BIT in new */ 550 + " csg %0,%1,%2\n" 551 + " jl 0b\n" 552 + : "=&d" (old), "=&d" (new), "=Q" (ptep[PTRS_PER_PTE]) 553 + : "Q" (ptep[PTRS_PER_PTE]) : "cc"); 554 + #endif 555 + return __pgste(new); 556 + } 557 + 558 + static inline void pgste_set_unlock(pte_t *ptep, pgste_t pgste) 553 559 { 554 560 #ifdef CONFIG_PGSTE 555 - unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE); 556 - clear_bit(RCP_PCL_BIT, pgste); 561 + asm( 562 + " nihh %1,0xff7f\n" /* clear RCP_PCL_BIT */ 563 + " stg %1,%0\n" 564 + : "=Q" (ptep[PTRS_PER_PTE]) 565 + : "d" (pgste_val(pgste)), "Q" (ptep[PTRS_PER_PTE]) : "cc"); 557 566 preempt_enable(); 558 567 #endif 559 568 } 560 569 561 - #include <linux/page-flags.h> 562 - 563 - static inline void ptep_rcp_copy(pte_t *ptep) 570 + static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste) 564 571 { 565 572 #ifdef CONFIG_PGSTE 566 - struct page *page = virt_to_page(pte_val(*ptep)); 567 - unsigned int skey; 568 - unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE); 573 + unsigned long pfn, bits; 574 + unsigned char skey; 569 575 570 - skey = page_get_storage_key(pte_val(*ptep) >> PAGE_SHIFT); 571 - if (skey & _PAGE_CHANGED) { 572 - set_bit_simple(RCP_GC_BIT, pgste); 573 - set_bit_simple(KVM_UD_BIT, pgste); 576 + pfn = pte_val(*ptep) >> PAGE_SHIFT; 577 + skey = page_get_storage_key(pfn); 578 + bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED); 579 + /* Clear page changed & referenced bit in the storage key */ 580 + if (bits) { 581 + skey ^= bits; 582 + page_set_storage_key(pfn, skey, 1); 574 583 } 575 - if (skey & _PAGE_REFERENCED) 576 - set_bit_simple(RCP_GR_BIT, pgste); 577 - if (test_and_clear_bit_simple(RCP_HC_BIT, pgste)) { 578 - SetPageDirty(page); 579 - set_bit_simple(KVM_UD_BIT, pgste); 580 - } 581 - if (test_and_clear_bit_simple(RCP_HR_BIT, pgste)) 582 - SetPageReferenced(page); 584 + /* Transfer page changed & referenced bit to guest bits in pgste */ 585 + pgste_val(pgste) |= bits << 48; /* RCP_GR_BIT & RCP_GC_BIT */ 586 + /* Get host changed & referenced bits from pgste */ 587 + bits |= (pgste_val(pgste) & (RCP_HR_BIT | RCP_HC_BIT)) >> 52; 588 + /* Clear host bits in pgste. */ 589 + pgste_val(pgste) &= ~(RCP_HR_BIT | RCP_HC_BIT); 590 + pgste_val(pgste) &= ~(RCP_ACC_BITS | RCP_FP_BIT); 591 + /* Copy page access key and fetch protection bit to pgste */ 592 + pgste_val(pgste) |= 593 + (unsigned long) (skey & (_PAGE_ACC_BITS | _PAGE_FP_BIT)) << 56; 594 + /* Transfer changed and referenced to kvm user bits */ 595 + pgste_val(pgste) |= bits << 45; /* KVM_UR_BIT & KVM_UC_BIT */ 596 + /* Transfer changed & referenced to pte sofware bits */ 597 + pte_val(*ptep) |= bits << 1; /* _PAGE_SWR & _PAGE_SWC */ 583 598 #endif 599 + return pgste; 600 + 601 + } 602 + 603 + static inline pgste_t pgste_update_young(pte_t *ptep, pgste_t pgste) 604 + { 605 + #ifdef CONFIG_PGSTE 606 + int young; 607 + 608 + young = page_reset_referenced(pte_val(*ptep) & PAGE_MASK); 609 + /* Transfer page referenced bit to pte software bit (host view) */ 610 + if (young || (pgste_val(pgste) & RCP_HR_BIT)) 611 + pte_val(*ptep) |= _PAGE_SWR; 612 + /* Clear host referenced bit in pgste. */ 613 + pgste_val(pgste) &= ~RCP_HR_BIT; 614 + /* Transfer page referenced bit to guest bit in pgste */ 615 + pgste_val(pgste) |= (unsigned long) young << 50; /* set RCP_GR_BIT */ 616 + #endif 617 + return pgste; 618 + 619 + } 620 + 621 + static inline void pgste_set_pte(pte_t *ptep, pgste_t pgste) 622 + { 623 + #ifdef CONFIG_PGSTE 624 + unsigned long pfn; 625 + unsigned long okey, nkey; 626 + 627 + pfn = pte_val(*ptep) >> PAGE_SHIFT; 628 + okey = nkey = page_get_storage_key(pfn); 629 + nkey &= ~(_PAGE_ACC_BITS | _PAGE_FP_BIT); 630 + /* Set page access key and fetch protection bit from pgste */ 631 + nkey |= (pgste_val(pgste) & (RCP_ACC_BITS | RCP_FP_BIT)) >> 56; 632 + if (okey != nkey) 633 + page_set_storage_key(pfn, nkey, 1); 634 + #endif 635 + } 636 + 637 + /* 638 + * Certain architectures need to do special things when PTEs 639 + * within a page table are directly modified. Thus, the following 640 + * hook is made available. 641 + */ 642 + static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, 643 + pte_t *ptep, pte_t entry) 644 + { 645 + pgste_t pgste; 646 + 647 + if (mm_has_pgste(mm)) { 648 + pgste = pgste_get_lock(ptep); 649 + pgste_set_pte(ptep, pgste); 650 + *ptep = entry; 651 + pgste_set_unlock(ptep, pgste); 652 + } else 653 + *ptep = entry; 584 654 } 585 655 586 656 /* ··· 671 587 672 588 static inline int pte_dirty(pte_t pte) 673 589 { 674 - /* A pte is neither clean nor dirty on s/390. The dirty bit 675 - * is in the storage key. See page_test_and_clear_dirty for 676 - * details. 677 - */ 590 + #ifdef CONFIG_PGSTE 591 + if (pte_val(pte) & _PAGE_SWC) 592 + return 1; 593 + #endif 678 594 return 0; 679 595 } 680 596 681 597 static inline int pte_young(pte_t pte) 682 598 { 683 - /* A pte is neither young nor old on s/390. The young bit 684 - * is in the storage key. See page_test_and_clear_young for 685 - * details. 686 - */ 599 + #ifdef CONFIG_PGSTE 600 + if (pte_val(pte) & _PAGE_SWR) 601 + return 1; 602 + #endif 687 603 return 0; 688 604 } 689 605 ··· 691 607 * pgd/pmd/pte modification functions 692 608 */ 693 609 694 - #ifndef __s390x__ 695 - 696 - #define pgd_clear(pgd) do { } while (0) 697 - #define pud_clear(pud) do { } while (0) 698 - 699 - #else /* __s390x__ */ 700 - 701 - static inline void pgd_clear_kernel(pgd_t * pgd) 610 + static inline void pgd_clear(pgd_t *pgd) 702 611 { 612 + #ifdef __s390x__ 703 613 if ((pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R2) 704 614 pgd_val(*pgd) = _REGION2_ENTRY_EMPTY; 705 - } 706 - 707 - static inline void pgd_clear(pgd_t * pgd) 708 - { 709 - pgd_clear_kernel(pgd); 710 - } 711 - 712 - static inline void pud_clear_kernel(pud_t *pud) 713 - { 714 - if ((pud_val(*pud) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3) 715 - pud_val(*pud) = _REGION3_ENTRY_EMPTY; 615 + #endif 716 616 } 717 617 718 618 static inline void pud_clear(pud_t *pud) 719 619 { 720 - pud_clear_kernel(pud); 620 + #ifdef __s390x__ 621 + if ((pud_val(*pud) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3) 622 + pud_val(*pud) = _REGION3_ENTRY_EMPTY; 623 + #endif 721 624 } 722 - #endif /* __s390x__ */ 723 625 724 - static inline void pmd_clear_kernel(pmd_t * pmdp) 626 + static inline void pmd_clear(pmd_t *pmdp) 725 627 { 726 628 pmd_val(*pmdp) = _SEGMENT_ENTRY_EMPTY; 727 - } 728 - 729 - static inline void pmd_clear(pmd_t *pmd) 730 - { 731 - pmd_clear_kernel(pmd); 732 629 } 733 630 734 631 static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) ··· 744 679 745 680 static inline pte_t pte_mkclean(pte_t pte) 746 681 { 747 - /* The only user of pte_mkclean is the fork() code. 748 - We must *not* clear the *physical* page dirty bit 749 - just because fork() wants to clear the dirty bit in 750 - *one* of the page's mappings. So we just do nothing. */ 682 + #ifdef CONFIG_PGSTE 683 + pte_val(pte) &= ~_PAGE_SWC; 684 + #endif 751 685 return pte; 752 686 } 753 687 754 688 static inline pte_t pte_mkdirty(pte_t pte) 755 689 { 756 - /* We do not explicitly set the dirty bit because the 757 - * sske instruction is slow. It is faster to let the 758 - * next instruction set the dirty bit. 759 - */ 760 690 return pte; 761 691 } 762 692 763 693 static inline pte_t pte_mkold(pte_t pte) 764 694 { 765 - /* S/390 doesn't keep its dirty/referenced bit in the pte. 766 - * There is no point in clearing the real referenced bit. 767 - */ 695 + #ifdef CONFIG_PGSTE 696 + pte_val(pte) &= ~_PAGE_SWR; 697 + #endif 768 698 return pte; 769 699 } 770 700 771 701 static inline pte_t pte_mkyoung(pte_t pte) 772 702 { 773 - /* S/390 doesn't keep its dirty/referenced bit in the pte. 774 - * There is no point in setting the real referenced bit. 775 - */ 776 703 return pte; 777 704 } 778 705 ··· 802 745 } 803 746 #endif 804 747 805 - #ifdef CONFIG_PGSTE 806 748 /* 807 - * Get (and clear) the user dirty bit for a PTE. 749 + * Get (and clear) the user dirty bit for a pte. 808 750 */ 809 - static inline int kvm_s390_test_and_clear_page_dirty(struct mm_struct *mm, 810 - pte_t *ptep) 751 + static inline int ptep_test_and_clear_user_dirty(struct mm_struct *mm, 752 + pte_t *ptep) 811 753 { 812 - int dirty; 813 - unsigned long *pgste; 814 - unsigned long pfn; 815 - struct page *page; 816 - unsigned int skey; 754 + pgste_t pgste; 755 + int dirty = 0; 817 756 818 - if (!mm->context.has_pgste) 819 - return -EINVAL; 820 - rcp_lock(ptep); 821 - pgste = (unsigned long *) (ptep + PTRS_PER_PTE); 822 - pfn = pte_val(*ptep) >> PAGE_SHIFT; 823 - page = pfn_to_page(pfn); 824 - skey = page_get_storage_key(pfn); 825 - if (skey & _PAGE_CHANGED) { 826 - set_bit_simple(RCP_GC_BIT, pgste); 827 - set_bit_simple(KVM_UD_BIT, pgste); 757 + if (mm_has_pgste(mm)) { 758 + pgste = pgste_get_lock(ptep); 759 + pgste = pgste_update_all(ptep, pgste); 760 + dirty = !!(pgste_val(pgste) & KVM_UC_BIT); 761 + pgste_val(pgste) &= ~KVM_UC_BIT; 762 + pgste_set_unlock(ptep, pgste); 763 + return dirty; 828 764 } 829 - if (test_and_clear_bit_simple(RCP_HC_BIT, pgste)) { 830 - SetPageDirty(page); 831 - set_bit_simple(KVM_UD_BIT, pgste); 832 - } 833 - dirty = test_and_clear_bit_simple(KVM_UD_BIT, pgste); 834 - if (skey & _PAGE_CHANGED) 835 - page_set_storage_key(pfn, skey & ~_PAGE_CHANGED, 1); 836 - rcp_unlock(ptep); 837 765 return dirty; 838 766 } 839 - #endif 767 + 768 + /* 769 + * Get (and clear) the user referenced bit for a pte. 770 + */ 771 + static inline int ptep_test_and_clear_user_young(struct mm_struct *mm, 772 + pte_t *ptep) 773 + { 774 + pgste_t pgste; 775 + int young = 0; 776 + 777 + if (mm_has_pgste(mm)) { 778 + pgste = pgste_get_lock(ptep); 779 + pgste = pgste_update_young(ptep, pgste); 780 + young = !!(pgste_val(pgste) & KVM_UR_BIT); 781 + pgste_val(pgste) &= ~KVM_UR_BIT; 782 + pgste_set_unlock(ptep, pgste); 783 + } 784 + return young; 785 + } 840 786 841 787 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG 842 788 static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, 843 789 unsigned long addr, pte_t *ptep) 844 790 { 845 - #ifdef CONFIG_PGSTE 846 - unsigned long pfn; 847 - int young; 848 - unsigned long *pgste; 791 + pgste_t pgste; 792 + pte_t pte; 849 793 850 - if (!vma->vm_mm->context.has_pgste) 851 - return 0; 852 - pfn = pte_val(*ptep) >> PAGE_SHIFT; 853 - pgste = (unsigned long *) (ptep + PTRS_PER_PTE); 854 - 855 - young = ((page_get_storage_key(pfn) & _PAGE_REFERENCED) != 0); 856 - rcp_lock(ptep); 857 - if (young) 858 - set_bit_simple(RCP_GR_BIT, pgste); 859 - young |= test_and_clear_bit_simple(RCP_HR_BIT, pgste); 860 - rcp_unlock(ptep); 861 - return young; 862 - #endif 794 + if (mm_has_pgste(vma->vm_mm)) { 795 + pgste = pgste_get_lock(ptep); 796 + pgste = pgste_update_young(ptep, pgste); 797 + pte = *ptep; 798 + *ptep = pte_mkold(pte); 799 + pgste_set_unlock(ptep, pgste); 800 + return pte_young(pte); 801 + } 863 802 return 0; 864 803 } 865 804 ··· 867 814 * On s390 reference bits are in storage key and never in TLB 868 815 * With virtualization we handle the reference bit, without we 869 816 * we can simply return */ 870 - #ifdef CONFIG_PGSTE 871 817 return ptep_test_and_clear_young(vma, address, ptep); 872 - #endif 873 - return 0; 874 818 } 875 819 876 820 static inline void __ptep_ipte(unsigned long address, pte_t *ptep) ··· 887 837 } 888 838 } 889 839 890 - static inline void ptep_invalidate(struct mm_struct *mm, 891 - unsigned long address, pte_t *ptep) 892 - { 893 - if (mm->context.has_pgste) { 894 - rcp_lock(ptep); 895 - __ptep_ipte(address, ptep); 896 - ptep_rcp_copy(ptep); 897 - pte_val(*ptep) = _PAGE_TYPE_EMPTY; 898 - rcp_unlock(ptep); 899 - return; 900 - } 901 - __ptep_ipte(address, ptep); 902 - pte_val(*ptep) = _PAGE_TYPE_EMPTY; 903 - } 904 - 905 840 /* 906 841 * This is hard to understand. ptep_get_and_clear and ptep_clear_flush 907 842 * both clear the TLB for the unmapped pte. The reason is that ··· 901 866 * is a nop. 902 867 */ 903 868 #define __HAVE_ARCH_PTEP_GET_AND_CLEAR 904 - #define ptep_get_and_clear(__mm, __address, __ptep) \ 905 - ({ \ 906 - pte_t __pte = *(__ptep); \ 907 - (__mm)->context.flush_mm = 1; \ 908 - if (atomic_read(&(__mm)->context.attach_count) > 1 || \ 909 - (__mm) != current->active_mm) \ 910 - ptep_invalidate(__mm, __address, __ptep); \ 911 - else \ 912 - pte_clear((__mm), (__address), (__ptep)); \ 913 - __pte; \ 914 - }) 869 + static inline pte_t ptep_get_and_clear(struct mm_struct *mm, 870 + unsigned long address, pte_t *ptep) 871 + { 872 + pgste_t pgste; 873 + pte_t pte; 874 + 875 + mm->context.flush_mm = 1; 876 + if (mm_has_pgste(mm)) 877 + pgste = pgste_get_lock(ptep); 878 + 879 + pte = *ptep; 880 + if (!mm_exclusive(mm)) 881 + __ptep_ipte(address, ptep); 882 + pte_val(*ptep) = _PAGE_TYPE_EMPTY; 883 + 884 + if (mm_has_pgste(mm)) { 885 + pgste = pgste_update_all(&pte, pgste); 886 + pgste_set_unlock(ptep, pgste); 887 + } 888 + return pte; 889 + } 890 + 891 + #define __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION 892 + static inline pte_t ptep_modify_prot_start(struct mm_struct *mm, 893 + unsigned long address, 894 + pte_t *ptep) 895 + { 896 + pte_t pte; 897 + 898 + mm->context.flush_mm = 1; 899 + if (mm_has_pgste(mm)) 900 + pgste_get_lock(ptep); 901 + 902 + pte = *ptep; 903 + if (!mm_exclusive(mm)) 904 + __ptep_ipte(address, ptep); 905 + return pte; 906 + } 907 + 908 + static inline void ptep_modify_prot_commit(struct mm_struct *mm, 909 + unsigned long address, 910 + pte_t *ptep, pte_t pte) 911 + { 912 + *ptep = pte; 913 + if (mm_has_pgste(mm)) 914 + pgste_set_unlock(ptep, *(pgste_t *)(ptep + PTRS_PER_PTE)); 915 + } 915 916 916 917 #define __HAVE_ARCH_PTEP_CLEAR_FLUSH 917 918 static inline pte_t ptep_clear_flush(struct vm_area_struct *vma, 918 919 unsigned long address, pte_t *ptep) 919 920 { 920 - pte_t pte = *ptep; 921 - ptep_invalidate(vma->vm_mm, address, ptep); 921 + pgste_t pgste; 922 + pte_t pte; 923 + 924 + if (mm_has_pgste(vma->vm_mm)) 925 + pgste = pgste_get_lock(ptep); 926 + 927 + pte = *ptep; 928 + __ptep_ipte(address, ptep); 929 + pte_val(*ptep) = _PAGE_TYPE_EMPTY; 930 + 931 + if (mm_has_pgste(vma->vm_mm)) { 932 + pgste = pgste_update_all(&pte, pgste); 933 + pgste_set_unlock(ptep, pgste); 934 + } 922 935 return pte; 923 936 } 924 937 ··· 979 896 */ 980 897 #define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL 981 898 static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, 982 - unsigned long addr, 899 + unsigned long address, 983 900 pte_t *ptep, int full) 984 901 { 985 - pte_t pte = *ptep; 902 + pgste_t pgste; 903 + pte_t pte; 986 904 987 - if (full) 988 - pte_clear(mm, addr, ptep); 989 - else 990 - ptep_invalidate(mm, addr, ptep); 905 + if (mm_has_pgste(mm)) 906 + pgste = pgste_get_lock(ptep); 907 + 908 + pte = *ptep; 909 + if (!full) 910 + __ptep_ipte(address, ptep); 911 + pte_val(*ptep) = _PAGE_TYPE_EMPTY; 912 + 913 + if (mm_has_pgste(mm)) { 914 + pgste = pgste_update_all(&pte, pgste); 915 + pgste_set_unlock(ptep, pgste); 916 + } 991 917 return pte; 992 918 } 993 919 994 920 #define __HAVE_ARCH_PTEP_SET_WRPROTECT 995 - #define ptep_set_wrprotect(__mm, __addr, __ptep) \ 996 - ({ \ 997 - pte_t __pte = *(__ptep); \ 998 - if (pte_write(__pte)) { \ 999 - (__mm)->context.flush_mm = 1; \ 1000 - if (atomic_read(&(__mm)->context.attach_count) > 1 || \ 1001 - (__mm) != current->active_mm) \ 1002 - ptep_invalidate(__mm, __addr, __ptep); \ 1003 - set_pte_at(__mm, __addr, __ptep, pte_wrprotect(__pte)); \ 1004 - } \ 1005 - }) 921 + static inline pte_t ptep_set_wrprotect(struct mm_struct *mm, 922 + unsigned long address, pte_t *ptep) 923 + { 924 + pgste_t pgste; 925 + pte_t pte = *ptep; 926 + 927 + if (pte_write(pte)) { 928 + mm->context.flush_mm = 1; 929 + if (mm_has_pgste(mm)) 930 + pgste = pgste_get_lock(ptep); 931 + 932 + if (!mm_exclusive(mm)) 933 + __ptep_ipte(address, ptep); 934 + *ptep = pte_wrprotect(pte); 935 + 936 + if (mm_has_pgste(mm)) 937 + pgste_set_unlock(ptep, pgste); 938 + } 939 + return pte; 940 + } 1006 941 1007 942 #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS 1008 - #define ptep_set_access_flags(__vma, __addr, __ptep, __entry, __dirty) \ 1009 - ({ \ 1010 - int __changed = !pte_same(*(__ptep), __entry); \ 1011 - if (__changed) { \ 1012 - ptep_invalidate((__vma)->vm_mm, __addr, __ptep); \ 1013 - set_pte_at((__vma)->vm_mm, __addr, __ptep, __entry); \ 1014 - } \ 1015 - __changed; \ 1016 - }) 943 + static inline int ptep_set_access_flags(struct vm_area_struct *vma, 944 + unsigned long address, pte_t *ptep, 945 + pte_t entry, int dirty) 946 + { 947 + pgste_t pgste; 948 + 949 + if (pte_same(*ptep, entry)) 950 + return 0; 951 + if (mm_has_pgste(vma->vm_mm)) 952 + pgste = pgste_get_lock(ptep); 953 + 954 + __ptep_ipte(address, ptep); 955 + *ptep = entry; 956 + 957 + if (mm_has_pgste(vma->vm_mm)) 958 + pgste_set_unlock(ptep, pgste); 959 + return 1; 960 + } 1017 961 1018 962 /* 1019 963 * Conversion functions: convert a page and protection to a page entry,
+2 -1
arch/s390/mm/init.c
··· 175 175 pmd = pmd_offset(pud, address); 176 176 pte = pte_offset_kernel(pmd, address); 177 177 if (!enable) { 178 - ptep_invalidate(&init_mm, address, pte); 178 + __ptep_ipte(address, pte); 179 + pte_val(*pte) = _PAGE_TYPE_EMPTY; 179 180 continue; 180 181 } 181 182 *pte = mk_pte_phys(address, __pgprot(_PAGE_TYPE_RW));
+1 -1
arch/s390/mm/pageattr.c
··· 28 28 29 29 pte = *ptep; 30 30 pte = set(pte); 31 - ptep_invalidate(&init_mm, addr, ptep); 31 + __ptep_ipte(addr, ptep); 32 32 *ptep = pte; 33 33 addr += PAGE_SIZE; 34 34 }
+7 -7
arch/s390/mm/vmem.c
··· 95 95 pu_dir = vmem_pud_alloc(); 96 96 if (!pu_dir) 97 97 goto out; 98 - pgd_populate_kernel(&init_mm, pg_dir, pu_dir); 98 + pgd_populate(&init_mm, pg_dir, pu_dir); 99 99 } 100 100 101 101 pu_dir = pud_offset(pg_dir, address); ··· 103 103 pm_dir = vmem_pmd_alloc(); 104 104 if (!pm_dir) 105 105 goto out; 106 - pud_populate_kernel(&init_mm, pu_dir, pm_dir); 106 + pud_populate(&init_mm, pu_dir, pm_dir); 107 107 } 108 108 109 109 pte = mk_pte_phys(address, __pgprot(ro ? _PAGE_RO : 0)); ··· 123 123 pt_dir = vmem_pte_alloc(); 124 124 if (!pt_dir) 125 125 goto out; 126 - pmd_populate_kernel(&init_mm, pm_dir, pt_dir); 126 + pmd_populate(&init_mm, pm_dir, pt_dir); 127 127 } 128 128 129 129 pt_dir = pte_offset_kernel(pm_dir, address); ··· 159 159 continue; 160 160 161 161 if (pmd_huge(*pm_dir)) { 162 - pmd_clear_kernel(pm_dir); 162 + pmd_clear(pm_dir); 163 163 address += HPAGE_SIZE - PAGE_SIZE; 164 164 continue; 165 165 } ··· 192 192 pu_dir = vmem_pud_alloc(); 193 193 if (!pu_dir) 194 194 goto out; 195 - pgd_populate_kernel(&init_mm, pg_dir, pu_dir); 195 + pgd_populate(&init_mm, pg_dir, pu_dir); 196 196 } 197 197 198 198 pu_dir = pud_offset(pg_dir, address); ··· 200 200 pm_dir = vmem_pmd_alloc(); 201 201 if (!pm_dir) 202 202 goto out; 203 - pud_populate_kernel(&init_mm, pu_dir, pm_dir); 203 + pud_populate(&init_mm, pu_dir, pm_dir); 204 204 } 205 205 206 206 pm_dir = pmd_offset(pu_dir, address); ··· 208 208 pt_dir = vmem_pte_alloc(); 209 209 if (!pt_dir) 210 210 goto out; 211 - pmd_populate_kernel(&init_mm, pm_dir, pt_dir); 211 + pmd_populate(&init_mm, pm_dir, pt_dir); 212 212 } 213 213 214 214 pt_dir = pte_offset_kernel(pm_dir, address);