summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorAndi Kleen <ak@suse.de>2008-02-04 16:48:09 +0100
committerIngo Molnar <mingo@elte.hu>2008-02-04 16:48:09 +0100
commitf07333fd149eb6826da26a89c3aff90324f270b0 (patch)
tree139557a0a7469e52dc8407c72dd70a011dee3884 /arch
parentb5360222273cb3e57a119c18eef42f59da4da87b (diff)
downloadlinux-f07333fd149eb6826da26a89c3aff90324f270b0.tar.gz
linux-f07333fd149eb6826da26a89c3aff90324f270b0.tar.bz2
linux-f07333fd149eb6826da26a89c3aff90324f270b0.zip
x86: implement gbpages support in change_page_attr()
Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/mm/pageattr.c17
1 files changed, 15 insertions, 2 deletions
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index 143fbafc948a..42ca3d8effad 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -281,7 +281,12 @@ static int try_preserve_large_page(pte_t *kpte, unsigned long address,
psize = PMD_PAGE_SIZE;
pmask = PMD_PAGE_MASK;
break;
+#ifdef CONFIG_X86_64
case PG_LEVEL_1G:
+ psize = PMD_PAGE_SIZE;
+ pmask = PMD_PAGE_MASK;
+ break;
+#endif
default:
res = -EINVAL;
goto out_unlock;
@@ -343,7 +348,7 @@ static int split_large_page(pte_t *kpte, unsigned long address)
{
pgprot_t ref_prot;
gfp_t gfp_flags = GFP_KERNEL;
- unsigned long flags, addr, pfn;
+ unsigned long flags, addr, pfn, pfninc = 1;
pte_t *pbase, *tmp;
struct page *base;
unsigned int i, level;
@@ -372,11 +377,19 @@ static int split_large_page(pte_t *kpte, unsigned long address)
#endif
ref_prot = pte_pgprot(pte_clrhuge(*kpte));
+#ifdef CONFIG_X86_64
+ if (level == PG_LEVEL_1G) {
+ pfninc = PMD_PAGE_SIZE >> PAGE_SHIFT;
+ pgprot_val(ref_prot) |= _PAGE_PSE;
+ addr &= PUD_PAGE_MASK;
+ }
+#endif
+
/*
* Get the target pfn from the original entry:
*/
pfn = pte_pfn(*kpte);
- for (i = 0; i < PTRS_PER_PTE; i++, pfn++)
+ for (i = 0; i < PTRS_PER_PTE; i++, pfn += pfninc)
set_pte(&pbase[i], pfn_pte(pfn, ref_prot));
/*