aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/mm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/mm')
-rw-r--r--arch/x86/mm/pat.c43
1 files changed, 28 insertions, 15 deletions
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c
index f88ac80530c0..8b08fb955274 100644
--- a/arch/x86/mm/pat.c
+++ b/arch/x86/mm/pat.c
@@ -601,12 +601,13 @@ void unmap_devmem(unsigned long pfn, unsigned long size, pgprot_t vma_prot)
601 * Reserved non RAM regions only and after successful reserve_memtype, 601 * Reserved non RAM regions only and after successful reserve_memtype,
602 * this func also keeps identity mapping (if any) in sync with this new prot. 602 * this func also keeps identity mapping (if any) in sync with this new prot.
603 */ 603 */
604static int reserve_pfn_range(u64 paddr, unsigned long size, pgprot_t vma_prot) 604static int reserve_pfn_range(u64 paddr, unsigned long size, pgprot_t *vma_prot,
605 int strict_prot)
605{ 606{
606 int is_ram = 0; 607 int is_ram = 0;
607 int id_sz, ret; 608 int id_sz, ret;
608 unsigned long flags; 609 unsigned long flags;
609 unsigned long want_flags = (pgprot_val(vma_prot) & _PAGE_CACHE_MASK); 610 unsigned long want_flags = (pgprot_val(*vma_prot) & _PAGE_CACHE_MASK);
610 611
611 is_ram = pagerange_is_ram(paddr, paddr + size); 612 is_ram = pagerange_is_ram(paddr, paddr + size);
612 613
@@ -625,15 +626,24 @@ static int reserve_pfn_range(u64 paddr, unsigned long size, pgprot_t vma_prot)
625 return ret; 626 return ret;
626 627
627 if (flags != want_flags) { 628 if (flags != want_flags) {
628 free_memtype(paddr, paddr + size); 629 if (strict_prot || !is_new_memtype_allowed(want_flags, flags)) {
629 printk(KERN_ERR 630 free_memtype(paddr, paddr + size);
630 "%s:%d map pfn expected mapping type %s for %Lx-%Lx, got %s\n", 631 printk(KERN_ERR "%s:%d map pfn expected mapping type %s"
631 current->comm, current->pid, 632 " for %Lx-%Lx, got %s\n",
632 cattr_name(want_flags), 633 current->comm, current->pid,
633 (unsigned long long)paddr, 634 cattr_name(want_flags),
634 (unsigned long long)(paddr + size), 635 (unsigned long long)paddr,
635 cattr_name(flags)); 636 (unsigned long long)(paddr + size),
636 return -EINVAL; 637 cattr_name(flags));
638 return -EINVAL;
639 }
640 /*
641 * We allow returning different type than the one requested in
642 * non strict case.
643 */
644 *vma_prot = __pgprot((pgprot_val(*vma_prot) &
645 (~_PAGE_CACHE_MASK)) |
646 flags);
637 } 647 }
638 648
639 /* Need to keep identity mapping in sync */ 649 /* Need to keep identity mapping in sync */
@@ -689,6 +699,7 @@ int track_pfn_vma_copy(struct vm_area_struct *vma)
689 unsigned long vma_start = vma->vm_start; 699 unsigned long vma_start = vma->vm_start;
690 unsigned long vma_end = vma->vm_end; 700 unsigned long vma_end = vma->vm_end;
691 unsigned long vma_size = vma_end - vma_start; 701 unsigned long vma_size = vma_end - vma_start;
702 pgprot_t pgprot;
692 703
693 if (!pat_enabled) 704 if (!pat_enabled)
694 return 0; 705 return 0;
@@ -702,7 +713,8 @@ int track_pfn_vma_copy(struct vm_area_struct *vma)
702 WARN_ON_ONCE(1); 713 WARN_ON_ONCE(1);
703 return -EINVAL; 714 return -EINVAL;
704 } 715 }
705 return reserve_pfn_range(paddr, vma_size, __pgprot(prot)); 716 pgprot = __pgprot(prot);
717 return reserve_pfn_range(paddr, vma_size, &pgprot, 1);
706 } 718 }
707 719
708 /* reserve entire vma page by page, using pfn and prot from pte */ 720 /* reserve entire vma page by page, using pfn and prot from pte */
@@ -710,7 +722,8 @@ int track_pfn_vma_copy(struct vm_area_struct *vma)
710 if (follow_phys(vma, vma_start + i, 0, &prot, &paddr)) 722 if (follow_phys(vma, vma_start + i, 0, &prot, &paddr))
711 continue; 723 continue;
712 724
713 retval = reserve_pfn_range(paddr, PAGE_SIZE, __pgprot(prot)); 725 pgprot = __pgprot(prot);
726 retval = reserve_pfn_range(paddr, PAGE_SIZE, &pgprot, 1);
714 if (retval) 727 if (retval)
715 goto cleanup_ret; 728 goto cleanup_ret;
716 } 729 }
@@ -758,14 +771,14 @@ int track_pfn_vma_new(struct vm_area_struct *vma, pgprot_t *prot,
758 if (is_linear_pfn_mapping(vma)) { 771 if (is_linear_pfn_mapping(vma)) {
759 /* reserve the whole chunk starting from vm_pgoff */ 772 /* reserve the whole chunk starting from vm_pgoff */
760 paddr = (resource_size_t)vma->vm_pgoff << PAGE_SHIFT; 773 paddr = (resource_size_t)vma->vm_pgoff << PAGE_SHIFT;
761 return reserve_pfn_range(paddr, vma_size, *prot); 774 return reserve_pfn_range(paddr, vma_size, prot, 0);
762 } 775 }
763 776
764 /* reserve page by page using pfn and size */ 777 /* reserve page by page using pfn and size */
765 base_paddr = (resource_size_t)pfn << PAGE_SHIFT; 778 base_paddr = (resource_size_t)pfn << PAGE_SHIFT;
766 for (i = 0; i < size; i += PAGE_SIZE) { 779 for (i = 0; i < size; i += PAGE_SIZE) {
767 paddr = base_paddr + i; 780 paddr = base_paddr + i;
768 retval = reserve_pfn_range(paddr, PAGE_SIZE, *prot); 781 retval = reserve_pfn_range(paddr, PAGE_SIZE, prot, 0);
769 if (retval) 782 if (retval)
770 goto cleanup_ret; 783 goto cleanup_ret;
771 } 784 }