aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/mm/pageattr.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/mm/pageattr.c')
-rw-r--r--arch/x86/mm/pageattr.c105
1 files changed, 97 insertions, 8 deletions
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index 7b79f6be4e7d..7d9517abc9af 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -9,6 +9,8 @@
9#include <linux/slab.h> 9#include <linux/slab.h>
10#include <linux/mm.h> 10#include <linux/mm.h>
11#include <linux/interrupt.h> 11#include <linux/interrupt.h>
12#include <linux/seq_file.h>
13#include <linux/debugfs.h>
12 14
13#include <asm/e820.h> 15#include <asm/e820.h>
14#include <asm/processor.h> 16#include <asm/processor.h>
@@ -17,6 +19,7 @@
17#include <asm/uaccess.h> 19#include <asm/uaccess.h>
18#include <asm/pgalloc.h> 20#include <asm/pgalloc.h>
19#include <asm/proto.h> 21#include <asm/proto.h>
22#include <asm/pat.h>
20 23
21/* 24/*
22 * The current flushing context - we pass it instead of 5 arguments: 25 * The current flushing context - we pass it instead of 5 arguments:
@@ -28,6 +31,7 @@ struct cpa_data {
28 int numpages; 31 int numpages;
29 int flushtlb; 32 int flushtlb;
30 unsigned long pfn; 33 unsigned long pfn;
34 unsigned force_split : 1;
31}; 35};
32 36
33#ifdef CONFIG_X86_64 37#ifdef CONFIG_X86_64
@@ -259,6 +263,9 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
259 int i, do_split = 1; 263 int i, do_split = 1;
260 unsigned int level; 264 unsigned int level;
261 265
266 if (cpa->force_split)
267 return 1;
268
262 spin_lock_irqsave(&pgd_lock, flags); 269 spin_lock_irqsave(&pgd_lock, flags);
263 /* 270 /*
264 * Check for races, another CPU might have split this page 271 * Check for races, another CPU might have split this page
@@ -693,7 +700,8 @@ static inline int cache_attr(pgprot_t attr)
693} 700}
694 701
695static int change_page_attr_set_clr(unsigned long addr, int numpages, 702static int change_page_attr_set_clr(unsigned long addr, int numpages,
696 pgprot_t mask_set, pgprot_t mask_clr) 703 pgprot_t mask_set, pgprot_t mask_clr,
704 int force_split)
697{ 705{
698 struct cpa_data cpa; 706 struct cpa_data cpa;
699 int ret, cache, checkalias; 707 int ret, cache, checkalias;
@@ -704,7 +712,7 @@ static int change_page_attr_set_clr(unsigned long addr, int numpages,
704 */ 712 */
705 mask_set = canon_pgprot(mask_set); 713 mask_set = canon_pgprot(mask_set);
706 mask_clr = canon_pgprot(mask_clr); 714 mask_clr = canon_pgprot(mask_clr);
707 if (!pgprot_val(mask_set) && !pgprot_val(mask_clr)) 715 if (!pgprot_val(mask_set) && !pgprot_val(mask_clr) && !force_split)
708 return 0; 716 return 0;
709 717
710 /* Ensure we are PAGE_SIZE aligned */ 718 /* Ensure we are PAGE_SIZE aligned */
@@ -721,6 +729,7 @@ static int change_page_attr_set_clr(unsigned long addr, int numpages,
721 cpa.mask_set = mask_set; 729 cpa.mask_set = mask_set;
722 cpa.mask_clr = mask_clr; 730 cpa.mask_clr = mask_clr;
723 cpa.flushtlb = 0; 731 cpa.flushtlb = 0;
732 cpa.force_split = force_split;
724 733
725 /* No alias checking for _NX bit modifications */ 734 /* No alias checking for _NX bit modifications */
726 checkalias = (pgprot_val(mask_set) | pgprot_val(mask_clr)) != _PAGE_NX; 735 checkalias = (pgprot_val(mask_set) | pgprot_val(mask_clr)) != _PAGE_NX;
@@ -759,26 +768,61 @@ out:
759static inline int change_page_attr_set(unsigned long addr, int numpages, 768static inline int change_page_attr_set(unsigned long addr, int numpages,
760 pgprot_t mask) 769 pgprot_t mask)
761{ 770{
762 return change_page_attr_set_clr(addr, numpages, mask, __pgprot(0)); 771 return change_page_attr_set_clr(addr, numpages, mask, __pgprot(0), 0);
763} 772}
764 773
765static inline int change_page_attr_clear(unsigned long addr, int numpages, 774static inline int change_page_attr_clear(unsigned long addr, int numpages,
766 pgprot_t mask) 775 pgprot_t mask)
767{ 776{
768 return change_page_attr_set_clr(addr, numpages, __pgprot(0), mask); 777 return change_page_attr_set_clr(addr, numpages, __pgprot(0), mask, 0);
769} 778}
770 779
771int set_memory_uc(unsigned long addr, int numpages) 780int _set_memory_uc(unsigned long addr, int numpages)
772{ 781{
773 return change_page_attr_set(addr, numpages, 782 return change_page_attr_set(addr, numpages,
774 __pgprot(_PAGE_PCD)); 783 __pgprot(_PAGE_CACHE_UC));
784}
785
786int set_memory_uc(unsigned long addr, int numpages)
787{
788 if (reserve_memtype(addr, addr + numpages * PAGE_SIZE,
789 _PAGE_CACHE_UC, NULL))
790 return -EINVAL;
791
792 return _set_memory_uc(addr, numpages);
775} 793}
776EXPORT_SYMBOL(set_memory_uc); 794EXPORT_SYMBOL(set_memory_uc);
777 795
778int set_memory_wb(unsigned long addr, int numpages) 796int _set_memory_wc(unsigned long addr, int numpages)
797{
798 return change_page_attr_set(addr, numpages,
799 __pgprot(_PAGE_CACHE_WC));
800}
801
802int set_memory_wc(unsigned long addr, int numpages)
803{
804 if (!pat_wc_enabled)
805 return set_memory_uc(addr, numpages);
806
807 if (reserve_memtype(addr, addr + numpages * PAGE_SIZE,
808 _PAGE_CACHE_WC, NULL))
809 return -EINVAL;
810
811 return _set_memory_wc(addr, numpages);
812}
813EXPORT_SYMBOL(set_memory_wc);
814
815int _set_memory_wb(unsigned long addr, int numpages)
779{ 816{
780 return change_page_attr_clear(addr, numpages, 817 return change_page_attr_clear(addr, numpages,
781 __pgprot(_PAGE_PCD | _PAGE_PWT)); 818 __pgprot(_PAGE_CACHE_MASK));
819}
820
821int set_memory_wb(unsigned long addr, int numpages)
822{
823 free_memtype(addr, addr + numpages * PAGE_SIZE);
824
825 return _set_memory_wb(addr, numpages);
782} 826}
783EXPORT_SYMBOL(set_memory_wb); 827EXPORT_SYMBOL(set_memory_wb);
784 828
@@ -809,6 +853,12 @@ int set_memory_np(unsigned long addr, int numpages)
809 return change_page_attr_clear(addr, numpages, __pgprot(_PAGE_PRESENT)); 853 return change_page_attr_clear(addr, numpages, __pgprot(_PAGE_PRESENT));
810} 854}
811 855
856int set_memory_4k(unsigned long addr, int numpages)
857{
858 return change_page_attr_set_clr(addr, numpages, __pgprot(0),
859 __pgprot(0), 1);
860}
861
812int set_pages_uc(struct page *page, int numpages) 862int set_pages_uc(struct page *page, int numpages)
813{ 863{
814 unsigned long addr = (unsigned long)page_address(page); 864 unsigned long addr = (unsigned long)page_address(page);
@@ -918,6 +968,45 @@ void kernel_map_pages(struct page *page, int numpages, int enable)
918 cpa_fill_pool(NULL); 968 cpa_fill_pool(NULL);
919} 969}
920 970
971#ifdef CONFIG_DEBUG_FS
972static int dpa_show(struct seq_file *m, void *v)
973{
974 seq_puts(m, "DEBUG_PAGEALLOC\n");
975 seq_printf(m, "pool_size : %lu\n", pool_size);
976 seq_printf(m, "pool_pages : %lu\n", pool_pages);
977 seq_printf(m, "pool_low : %lu\n", pool_low);
978 seq_printf(m, "pool_used : %lu\n", pool_used);
979 seq_printf(m, "pool_failed : %lu\n", pool_failed);
980
981 return 0;
982}
983
984static int dpa_open(struct inode *inode, struct file *filp)
985{
986 return single_open(filp, dpa_show, NULL);
987}
988
989static const struct file_operations dpa_fops = {
990 .open = dpa_open,
991 .read = seq_read,
992 .llseek = seq_lseek,
993 .release = single_release,
994};
995
996int __init debug_pagealloc_proc_init(void)
997{
998 struct dentry *de;
999
1000 de = debugfs_create_file("debug_pagealloc", 0600, NULL, NULL,
1001 &dpa_fops);
1002 if (!de)
1003 return -ENOMEM;
1004
1005 return 0;
1006}
1007__initcall(debug_pagealloc_proc_init);
1008#endif
1009
921#ifdef CONFIG_HIBERNATION 1010#ifdef CONFIG_HIBERNATION
922 1011
923bool kernel_page_present(struct page *page) 1012bool kernel_page_present(struct page *page)