diff options
author | venkatesh.pallipadi@intel.com <venkatesh.pallipadi@intel.com> | 2009-03-19 17:51:14 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-03-20 05:34:48 -0400 |
commit | 9ae2847591c857bed44bc094b908b412bfa1b244 (patch) | |
tree | 566ffc65293442b05278b6bbb6479b5a254cd64f | |
parent | 728c9518873de0bbb92b66daa1943b12e5b9f80f (diff) |
x86, PAT: Add support for struct page pointer array in cpa set_clr
Add struct page array pointer to cpa struct and CPA_PAGES_ARRAY.
With that we can add change_page_attr_set_clr() a parameter to pass
struct page array pointer and that can be handled by the underlying
cpa code.
cpa_flush_array() is also changed to support both addr array or
struct page pointer array, depending on the flag.
Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Cc: arjan@infradead.org
Cc: eric@anholt.net
Cc: airlied@redhat.com
LKML-Reference: <20090319215358.758513000@intel.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | arch/x86/mm/pageattr.c | 79 |
1 files changed, 50 insertions, 29 deletions
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 69009afa98c0..e5c257fb41e2 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c | |||
@@ -34,6 +34,7 @@ struct cpa_data { | |||
34 | unsigned long pfn; | 34 | unsigned long pfn; |
35 | unsigned force_split : 1; | 35 | unsigned force_split : 1; |
36 | int curpage; | 36 | int curpage; |
37 | struct page **pages; | ||
37 | }; | 38 | }; |
38 | 39 | ||
39 | /* | 40 | /* |
@@ -46,6 +47,7 @@ static DEFINE_SPINLOCK(cpa_lock); | |||
46 | 47 | ||
47 | #define CPA_FLUSHTLB 1 | 48 | #define CPA_FLUSHTLB 1 |
48 | #define CPA_ARRAY 2 | 49 | #define CPA_ARRAY 2 |
50 | #define CPA_PAGES_ARRAY 4 | ||
49 | 51 | ||
50 | #ifdef CONFIG_PROC_FS | 52 | #ifdef CONFIG_PROC_FS |
51 | static unsigned long direct_pages_count[PG_LEVEL_NUM]; | 53 | static unsigned long direct_pages_count[PG_LEVEL_NUM]; |
@@ -202,10 +204,10 @@ static void cpa_flush_range(unsigned long start, int numpages, int cache) | |||
202 | } | 204 | } |
203 | } | 205 | } |
204 | 206 | ||
205 | static void cpa_flush_array(unsigned long *start, int numpages, int cache) | 207 | static void cpa_flush_array(unsigned long *start, int numpages, int cache, |
208 | int in_flags, struct page **pages) | ||
206 | { | 209 | { |
207 | unsigned int i, level; | 210 | unsigned int i, level; |
208 | unsigned long *addr; | ||
209 | 211 | ||
210 | BUG_ON(irqs_disabled()); | 212 | BUG_ON(irqs_disabled()); |
211 | 213 | ||
@@ -226,14 +228,22 @@ static void cpa_flush_array(unsigned long *start, int numpages, int cache) | |||
226 | * will cause all other CPUs to flush the same | 228 | * will cause all other CPUs to flush the same |
227 | * cachelines: | 229 | * cachelines: |
228 | */ | 230 | */ |
229 | for (i = 0, addr = start; i < numpages; i++, addr++) { | 231 | for (i = 0; i < numpages; i++) { |
230 | pte_t *pte = lookup_address(*addr, &level); | 232 | unsigned long addr; |
233 | pte_t *pte; | ||
234 | |||
235 | if (in_flags & CPA_PAGES_ARRAY) | ||
236 | addr = (unsigned long)page_address(pages[i]); | ||
237 | else | ||
238 | addr = start[i]; | ||
239 | |||
240 | pte = lookup_address(addr, &level); | ||
231 | 241 | ||
232 | /* | 242 | /* |
233 | * Only flush present addresses: | 243 | * Only flush present addresses: |
234 | */ | 244 | */ |
235 | if (pte && (pte_val(*pte) & _PAGE_PRESENT)) | 245 | if (pte && (pte_val(*pte) & _PAGE_PRESENT)) |
236 | clflush_cache_range((void *) *addr, PAGE_SIZE); | 246 | clflush_cache_range((void *)addr, PAGE_SIZE); |
237 | } | 247 | } |
238 | } | 248 | } |
239 | 249 | ||
@@ -585,7 +595,9 @@ static int __change_page_attr(struct cpa_data *cpa, int primary) | |||
585 | unsigned int level; | 595 | unsigned int level; |
586 | pte_t *kpte, old_pte; | 596 | pte_t *kpte, old_pte; |
587 | 597 | ||
588 | if (cpa->flags & CPA_ARRAY) | 598 | if (cpa->flags & CPA_PAGES_ARRAY) |
599 | address = (unsigned long)page_address(cpa->pages[cpa->curpage]); | ||
600 | else if (cpa->flags & CPA_ARRAY) | ||
589 | address = cpa->vaddr[cpa->curpage]; | 601 | address = cpa->vaddr[cpa->curpage]; |
590 | else | 602 | else |
591 | address = *cpa->vaddr; | 603 | address = *cpa->vaddr; |
@@ -688,7 +700,9 @@ static int cpa_process_alias(struct cpa_data *cpa) | |||
688 | * No need to redo, when the primary call touched the direct | 700 | * No need to redo, when the primary call touched the direct |
689 | * mapping already: | 701 | * mapping already: |
690 | */ | 702 | */ |
691 | if (cpa->flags & CPA_ARRAY) | 703 | if (cpa->flags & CPA_PAGES_ARRAY) |
704 | vaddr = (unsigned long)page_address(cpa->pages[cpa->curpage]); | ||
705 | else if (cpa->flags & CPA_ARRAY) | ||
692 | vaddr = cpa->vaddr[cpa->curpage]; | 706 | vaddr = cpa->vaddr[cpa->curpage]; |
693 | else | 707 | else |
694 | vaddr = *cpa->vaddr; | 708 | vaddr = *cpa->vaddr; |
@@ -699,7 +713,7 @@ static int cpa_process_alias(struct cpa_data *cpa) | |||
699 | alias_cpa = *cpa; | 713 | alias_cpa = *cpa; |
700 | temp_cpa_vaddr = (unsigned long) __va(cpa->pfn << PAGE_SHIFT); | 714 | temp_cpa_vaddr = (unsigned long) __va(cpa->pfn << PAGE_SHIFT); |
701 | alias_cpa.vaddr = &temp_cpa_vaddr; | 715 | alias_cpa.vaddr = &temp_cpa_vaddr; |
702 | alias_cpa.flags &= ~CPA_ARRAY; | 716 | alias_cpa.flags &= ~(CPA_PAGES_ARRAY | CPA_ARRAY); |
703 | 717 | ||
704 | 718 | ||
705 | ret = __change_page_attr_set_clr(&alias_cpa, 0); | 719 | ret = __change_page_attr_set_clr(&alias_cpa, 0); |
@@ -725,7 +739,7 @@ static int cpa_process_alias(struct cpa_data *cpa) | |||
725 | alias_cpa = *cpa; | 739 | alias_cpa = *cpa; |
726 | temp_cpa_vaddr = (cpa->pfn << PAGE_SHIFT) + __START_KERNEL_map - phys_base; | 740 | temp_cpa_vaddr = (cpa->pfn << PAGE_SHIFT) + __START_KERNEL_map - phys_base; |
727 | alias_cpa.vaddr = &temp_cpa_vaddr; | 741 | alias_cpa.vaddr = &temp_cpa_vaddr; |
728 | alias_cpa.flags &= ~CPA_ARRAY; | 742 | alias_cpa.flags &= ~(CPA_PAGES_ARRAY | CPA_ARRAY); |
729 | 743 | ||
730 | /* | 744 | /* |
731 | * The high mapping range is imprecise, so ignore the return value. | 745 | * The high mapping range is imprecise, so ignore the return value. |
@@ -746,7 +760,7 @@ static int __change_page_attr_set_clr(struct cpa_data *cpa, int checkalias) | |||
746 | */ | 760 | */ |
747 | cpa->numpages = numpages; | 761 | cpa->numpages = numpages; |
748 | /* for array changes, we can't use large page */ | 762 | /* for array changes, we can't use large page */ |
749 | if (cpa->flags & CPA_ARRAY) | 763 | if (cpa->flags & (CPA_ARRAY | CPA_PAGES_ARRAY)) |
750 | cpa->numpages = 1; | 764 | cpa->numpages = 1; |
751 | 765 | ||
752 | if (!debug_pagealloc) | 766 | if (!debug_pagealloc) |
@@ -770,7 +784,7 @@ static int __change_page_attr_set_clr(struct cpa_data *cpa, int checkalias) | |||
770 | */ | 784 | */ |
771 | BUG_ON(cpa->numpages > numpages); | 785 | BUG_ON(cpa->numpages > numpages); |
772 | numpages -= cpa->numpages; | 786 | numpages -= cpa->numpages; |
773 | if (cpa->flags & CPA_ARRAY) | 787 | if (cpa->flags & (CPA_PAGES_ARRAY | CPA_ARRAY)) |
774 | cpa->curpage++; | 788 | cpa->curpage++; |
775 | else | 789 | else |
776 | *cpa->vaddr += cpa->numpages * PAGE_SIZE; | 790 | *cpa->vaddr += cpa->numpages * PAGE_SIZE; |
@@ -787,7 +801,8 @@ static inline int cache_attr(pgprot_t attr) | |||
787 | 801 | ||
788 | static int change_page_attr_set_clr(unsigned long *addr, int numpages, | 802 | static int change_page_attr_set_clr(unsigned long *addr, int numpages, |
789 | pgprot_t mask_set, pgprot_t mask_clr, | 803 | pgprot_t mask_set, pgprot_t mask_clr, |
790 | int force_split, int in_flag) | 804 | int force_split, int in_flag, |
805 | struct page **pages) | ||
791 | { | 806 | { |
792 | struct cpa_data cpa; | 807 | struct cpa_data cpa; |
793 | int ret, cache, checkalias; | 808 | int ret, cache, checkalias; |
@@ -802,15 +817,7 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages, | |||
802 | return 0; | 817 | return 0; |
803 | 818 | ||
804 | /* Ensure we are PAGE_SIZE aligned */ | 819 | /* Ensure we are PAGE_SIZE aligned */ |
805 | if (!(in_flag & CPA_ARRAY)) { | 820 | if (in_flag & CPA_ARRAY) { |
806 | if (*addr & ~PAGE_MASK) { | ||
807 | *addr &= PAGE_MASK; | ||
808 | /* | ||
809 | * People should not be passing in unaligned addresses: | ||
810 | */ | ||
811 | WARN_ON_ONCE(1); | ||
812 | } | ||
813 | } else { | ||
814 | int i; | 821 | int i; |
815 | for (i = 0; i < numpages; i++) { | 822 | for (i = 0; i < numpages; i++) { |
816 | if (addr[i] & ~PAGE_MASK) { | 823 | if (addr[i] & ~PAGE_MASK) { |
@@ -818,6 +825,18 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages, | |||
818 | WARN_ON_ONCE(1); | 825 | WARN_ON_ONCE(1); |
819 | } | 826 | } |
820 | } | 827 | } |
828 | } else if (!(in_flag & CPA_PAGES_ARRAY)) { | ||
829 | /* | ||
830 | * in_flag of CPA_PAGES_ARRAY implies it is aligned. | ||
831 | * No need to cehck in that case | ||
832 | */ | ||
833 | if (*addr & ~PAGE_MASK) { | ||
834 | *addr &= PAGE_MASK; | ||
835 | /* | ||
836 | * People should not be passing in unaligned addresses: | ||
837 | */ | ||
838 | WARN_ON_ONCE(1); | ||
839 | } | ||
821 | } | 840 | } |
822 | 841 | ||
823 | /* Must avoid aliasing mappings in the highmem code */ | 842 | /* Must avoid aliasing mappings in the highmem code */ |
@@ -833,6 +852,7 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages, | |||
833 | arch_flush_lazy_mmu_mode(); | 852 | arch_flush_lazy_mmu_mode(); |
834 | 853 | ||
835 | cpa.vaddr = addr; | 854 | cpa.vaddr = addr; |
855 | cpa.pages = pages; | ||
836 | cpa.numpages = numpages; | 856 | cpa.numpages = numpages; |
837 | cpa.mask_set = mask_set; | 857 | cpa.mask_set = mask_set; |
838 | cpa.mask_clr = mask_clr; | 858 | cpa.mask_clr = mask_clr; |
@@ -840,8 +860,8 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages, | |||
840 | cpa.curpage = 0; | 860 | cpa.curpage = 0; |
841 | cpa.force_split = force_split; | 861 | cpa.force_split = force_split; |
842 | 862 | ||
843 | if (in_flag & CPA_ARRAY) | 863 | if (in_flag & (CPA_ARRAY | CPA_PAGES_ARRAY)) |
844 | cpa.flags |= CPA_ARRAY; | 864 | cpa.flags |= in_flag; |
845 | 865 | ||
846 | /* No alias checking for _NX bit modifications */ | 866 | /* No alias checking for _NX bit modifications */ |
847 | checkalias = (pgprot_val(mask_set) | pgprot_val(mask_clr)) != _PAGE_NX; | 867 | checkalias = (pgprot_val(mask_set) | pgprot_val(mask_clr)) != _PAGE_NX; |
@@ -867,9 +887,10 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages, | |||
867 | * wbindv): | 887 | * wbindv): |
868 | */ | 888 | */ |
869 | if (!ret && cpu_has_clflush) { | 889 | if (!ret && cpu_has_clflush) { |
870 | if (cpa.flags & CPA_ARRAY) | 890 | if (cpa.flags & (CPA_PAGES_ARRAY | CPA_ARRAY)) { |
871 | cpa_flush_array(addr, numpages, cache); | 891 | cpa_flush_array(addr, numpages, cache, |
872 | else | 892 | cpa.flags, pages); |
893 | } else | ||
873 | cpa_flush_range(*addr, numpages, cache); | 894 | cpa_flush_range(*addr, numpages, cache); |
874 | } else | 895 | } else |
875 | cpa_flush_all(cache); | 896 | cpa_flush_all(cache); |
@@ -889,14 +910,14 @@ static inline int change_page_attr_set(unsigned long *addr, int numpages, | |||
889 | pgprot_t mask, int array) | 910 | pgprot_t mask, int array) |
890 | { | 911 | { |
891 | return change_page_attr_set_clr(addr, numpages, mask, __pgprot(0), 0, | 912 | return change_page_attr_set_clr(addr, numpages, mask, __pgprot(0), 0, |
892 | (array ? CPA_ARRAY : 0)); | 913 | (array ? CPA_ARRAY : 0), NULL); |
893 | } | 914 | } |
894 | 915 | ||
895 | static inline int change_page_attr_clear(unsigned long *addr, int numpages, | 916 | static inline int change_page_attr_clear(unsigned long *addr, int numpages, |
896 | pgprot_t mask, int array) | 917 | pgprot_t mask, int array) |
897 | { | 918 | { |
898 | return change_page_attr_set_clr(addr, numpages, __pgprot(0), mask, 0, | 919 | return change_page_attr_set_clr(addr, numpages, __pgprot(0), mask, 0, |
899 | (array ? CPA_ARRAY : 0)); | 920 | (array ? CPA_ARRAY : 0), NULL); |
900 | } | 921 | } |
901 | 922 | ||
902 | int _set_memory_uc(unsigned long addr, int numpages) | 923 | int _set_memory_uc(unsigned long addr, int numpages) |
@@ -1044,7 +1065,7 @@ int set_memory_np(unsigned long addr, int numpages) | |||
1044 | int set_memory_4k(unsigned long addr, int numpages) | 1065 | int set_memory_4k(unsigned long addr, int numpages) |
1045 | { | 1066 | { |
1046 | return change_page_attr_set_clr(&addr, numpages, __pgprot(0), | 1067 | return change_page_attr_set_clr(&addr, numpages, __pgprot(0), |
1047 | __pgprot(0), 1, 0); | 1068 | __pgprot(0), 1, 0, NULL); |
1048 | } | 1069 | } |
1049 | 1070 | ||
1050 | int set_pages_uc(struct page *page, int numpages) | 1071 | int set_pages_uc(struct page *page, int numpages) |