aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/mm/pageattr.c10
-rw-r--r--arch/x86/mm/pat.c45
2 files changed, 38 insertions, 17 deletions
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index e89d24815f26..4cf30dee8161 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -555,10 +555,12 @@ repeat:
555 if (!pte_val(old_pte)) { 555 if (!pte_val(old_pte)) {
556 if (!primary) 556 if (!primary)
557 return 0; 557 return 0;
558 WARN(1, KERN_WARNING "CPA: called for zero pte. " 558
559 "vaddr = %lx cpa->vaddr = %lx\n", address, 559 /*
560 *cpa->vaddr); 560 * Special error value returned, indicating that the mapping
561 return -EINVAL; 561 * did not exist at this address.
562 */
563 return -EFAULT;
562 } 564 }
563 565
564 if (level == PG_LEVEL_4K) { 566 if (level == PG_LEVEL_4K) {
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c
index 8b08fb955274..160c42d3eb8f 100644
--- a/arch/x86/mm/pat.c
+++ b/arch/x86/mm/pat.c
@@ -505,6 +505,35 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size)
505} 505}
506#endif /* CONFIG_STRICT_DEVMEM */ 506#endif /* CONFIG_STRICT_DEVMEM */
507 507
508/*
509 * Change the memory type for the physial address range in kernel identity
510 * mapping space if that range is a part of identity map.
511 */
512static int kernel_map_sync_memtype(u64 base, unsigned long size,
513 unsigned long flags)
514{
515 unsigned long id_sz;
516 int ret;
517
518 if (!pat_enabled || base >= __pa(high_memory))
519 return 0;
520
521 id_sz = (__pa(high_memory) < base + size) ?
522 __pa(high_memory) - base :
523 size;
524
525 ret = ioremap_change_attr((unsigned long)__va(base), id_sz, flags);
526 /*
527 * -EFAULT return means that the addr was not valid and did not have
528 * any identity mapping. That case is a success for
529 * kernel_map_sync_memtype.
530 */
531 if (ret == -EFAULT)
532 ret = 0;
533
534 return ret;
535}
536
508int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn, 537int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn,
509 unsigned long size, pgprot_t *vma_prot) 538 unsigned long size, pgprot_t *vma_prot)
510{ 539{
@@ -555,9 +584,7 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn,
555 if (retval < 0) 584 if (retval < 0)
556 return 0; 585 return 0;
557 586
558 if (((pfn < max_low_pfn_mapped) || 587 if (kernel_map_sync_memtype(offset, size, flags)) {
559 (pfn >= (1UL<<(32 - PAGE_SHIFT)) && pfn < max_pfn_mapped)) &&
560 ioremap_change_attr((unsigned long)__va(offset), size, flags) < 0) {
561 free_memtype(offset, offset + size); 588 free_memtype(offset, offset + size);
562 printk(KERN_INFO 589 printk(KERN_INFO
563 "%s:%d /dev/mem ioremap_change_attr failed %s for %Lx-%Lx\n", 590 "%s:%d /dev/mem ioremap_change_attr failed %s for %Lx-%Lx\n",
@@ -605,7 +632,7 @@ static int reserve_pfn_range(u64 paddr, unsigned long size, pgprot_t *vma_prot,
605 int strict_prot) 632 int strict_prot)
606{ 633{
607 int is_ram = 0; 634 int is_ram = 0;
608 int id_sz, ret; 635 int ret;
609 unsigned long flags; 636 unsigned long flags;
610 unsigned long want_flags = (pgprot_val(*vma_prot) & _PAGE_CACHE_MASK); 637 unsigned long want_flags = (pgprot_val(*vma_prot) & _PAGE_CACHE_MASK);
611 638
@@ -646,15 +673,7 @@ static int reserve_pfn_range(u64 paddr, unsigned long size, pgprot_t *vma_prot,
646 flags); 673 flags);
647 } 674 }
648 675
649 /* Need to keep identity mapping in sync */ 676 if (kernel_map_sync_memtype(paddr, size, flags)) {
650 if (paddr >= __pa(high_memory))
651 return 0;
652
653 id_sz = (__pa(high_memory) < paddr + size) ?
654 __pa(high_memory) - paddr :
655 size;
656
657 if (ioremap_change_attr((unsigned long)__va(paddr), id_sz, flags) < 0) {
658 free_memtype(paddr, paddr + size); 677 free_memtype(paddr, paddr + size);
659 printk(KERN_ERR 678 printk(KERN_ERR
660 "%s:%d reserve_pfn_range ioremap_change_attr failed %s " 679 "%s:%d reserve_pfn_range ioremap_change_attr failed %s "