aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/mm/pageattr.c
diff options
context:
space:
mode:
authorvenkatesh.pallipadi@intel.com <venkatesh.pallipadi@intel.com>2009-03-19 17:51:14 -0400
committerIngo Molnar <mingo@elte.hu>2009-03-20 05:34:48 -0400
commit9ae2847591c857bed44bc094b908b412bfa1b244 (patch)
tree566ffc65293442b05278b6bbb6479b5a254cd64f /arch/x86/mm/pageattr.c
parent728c9518873de0bbb92b66daa1943b12e5b9f80f (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>
Diffstat (limited to 'arch/x86/mm/pageattr.c')
-rw-r--r--arch/x86/mm/pageattr.c79
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
51static unsigned long direct_pages_count[PG_LEVEL_NUM]; 53static 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
205static void cpa_flush_array(unsigned long *start, int numpages, int cache) 207static 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
788static int change_page_attr_set_clr(unsigned long *addr, int numpages, 802static 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
895static inline int change_page_attr_clear(unsigned long *addr, int numpages, 916static 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
902int _set_memory_uc(unsigned long addr, int numpages) 923int _set_memory_uc(unsigned long addr, int numpages)
@@ -1044,7 +1065,7 @@ int set_memory_np(unsigned long addr, int numpages)
1044int set_memory_4k(unsigned long addr, int numpages) 1065int 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
1050int set_pages_uc(struct page *page, int numpages) 1071int set_pages_uc(struct page *page, int numpages)