aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/mm
diff options
context:
space:
mode:
authorvenkatesh.pallipadi@intel.com <venkatesh.pallipadi@intel.com>2009-01-09 19:13:14 -0500
committerIngo Molnar <mingo@elte.hu>2009-01-13 13:13:02 -0500
commit58dab916dfb57328d50deb0aa9b3fc92efa248ff (patch)
tree895d4cf0e9270a1f6de215dd98dffa7548fc3897 /arch/x86/mm
parentcdecff6864a1cd352a41d44a65e7451b8ef5cee2 (diff)
x86 PAT: remove CPA WARN_ON for zero pte
Impact: reduce scope of debug check - avoid warnings The logic to find whether identity map exists or not using high_memory or max_low_pfn_mapped/max_pfn_mapped are not complete as the memory withing the range may not be mapped if there is a unusable hole in e820. Specifically, on my test system I started seeing these warnings with tools like hwinfo, acpidump trying to map ACPI region. [ 27.400018] ------------[ cut here ]------------ [ 27.400344] WARNING: at /home/venkip/src/linus/linux-2.6/arch/x86/mm/pageattr.c:560 __change_page_attr_set_clr+0xf3/0x8b8() [ 27.400821] Hardware name: X7DB8 [ 27.401070] CPA: called for zero pte. vaddr = ffff8800cff6a000 cpa->vaddr = ffff8800cff6a000 [ 27.401569] Modules linked in: [ 27.401882] Pid: 4913, comm: dmidecode Not tainted 2.6.28-05716-gfe0bdec #586 [ 27.402141] Call Trace: [ 27.402488] [<ffffffff80237c21>] warn_slowpath+0xd3/0x10f [ 27.402749] [<ffffffff80274ade>] ? find_get_page+0xb3/0xc9 [ 27.403028] [<ffffffff80274a2b>] ? find_get_page+0x0/0xc9 [ 27.403333] [<ffffffff80226425>] __change_page_attr_set_clr+0xf3/0x8b8 [ 27.403628] [<ffffffff8028ec99>] ? __purge_vmap_area_lazy+0x192/0x1a1 [ 27.403883] [<ffffffff8028eb52>] ? __purge_vmap_area_lazy+0x4b/0x1a1 [ 27.404172] [<ffffffff80290268>] ? vm_unmap_aliases+0x1ab/0x1bb [ 27.404512] [<ffffffff80290105>] ? vm_unmap_aliases+0x48/0x1bb [ 27.404766] [<ffffffff80226d28>] change_page_attr_set_clr+0x13e/0x2e6 [ 27.405026] [<ffffffff80698fa7>] ? _spin_unlock+0x26/0x2a [ 27.405292] [<ffffffff80227e6a>] ? reserve_memtype+0x19b/0x4e3 [ 27.405590] [<ffffffff80226ffd>] _set_memory_wb+0x22/0x24 [ 27.405844] [<ffffffff80225d28>] ioremap_change_attr+0x26/0x28 [ 27.406097] [<ffffffff80228355>] reserve_pfn_range+0x1a3/0x235 [ 27.406427] [<ffffffff80228430>] track_pfn_vma_new+0x49/0xb3 [ 27.406686] [<ffffffff80286c46>] remap_pfn_range+0x94/0x32c [ 27.406940] [<ffffffff8022878d>] ? phys_mem_access_prot_allowed+0xb5/0x1a8 [ 27.407209] [<ffffffff803e9bf4>] mmap_mem+0x75/0x9d [ 27.407523] [<ffffffff8028b3b4>] mmap_region+0x2cf/0x53e [ 27.407776] [<ffffffff8028b8cc>] do_mmap_pgoff+0x2a9/0x30d [ 27.408034] [<ffffffff8020f4a4>] sys_mmap+0x92/0xce [ 27.408339] [<ffffffff8020b65b>] system_call_fastpath+0x16/0x1b [ 27.408614] ---[ end trace 4b16ad70c09a602d ]--- [ 27.408871] dmidecode:4913 reserve_pfn_range ioremap_change_attr failed write-back for cff6a000-cff6b000 This is wih track_pfn_vma_new trying to keep identity map in sync. The address cff6a000 is the ACPI region according to e820. [ 0.000000] BIOS-provided physical RAM map: [ 0.000000] BIOS-e820: 0000000000000000 - 000000000009c000 (usable) [ 0.000000] BIOS-e820: 000000000009c000 - 00000000000a0000 (reserved) [ 0.000000] BIOS-e820: 00000000000cc000 - 00000000000d0000 (reserved) [ 0.000000] BIOS-e820: 00000000000e4000 - 0000000000100000 (reserved) [ 0.000000] BIOS-e820: 0000000000100000 - 00000000cff60000 (usable) [ 0.000000] BIOS-e820: 00000000cff60000 - 00000000cff69000 (ACPI data) [ 0.000000] BIOS-e820: 00000000cff69000 - 00000000cff80000 (ACPI NVS) [ 0.000000] BIOS-e820: 00000000cff80000 - 00000000d0000000 (reserved) [ 0.000000] BIOS-e820: 00000000e0000000 - 00000000f0000000 (reserved) [ 0.000000] BIOS-e820: 00000000fec00000 - 00000000fec10000 (reserved) [ 0.000000] BIOS-e820: 00000000fee00000 - 00000000fee01000 (reserved) [ 0.000000] BIOS-e820: 00000000ff000000 - 0000000100000000 (reserved) [ 0.000000] BIOS-e820: 0000000100000000 - 0000000230000000 (usable) And is not mapped as per init_memory_mapping. [ 0.000000] init_memory_mapping: 0000000000000000-00000000cff60000 [ 0.000000] init_memory_mapping: 0000000100000000-0000000230000000 We can add logic to check for this. But, there can also be other holes in identity map when we have 1GB of aligned reserved space in e820. This patch handles it by removing the WARN_ON and returning a specific error value (EFAULT) to indicate that the address does not have any identity mapping. The code that tries to keep identity map in sync can ignore this error, with other callers of cpa still getting error here. Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/mm')
-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 "