diff options
author | Suresh Siddha <suresh.b.siddha@intel.com> | 2012-10-08 19:28:29 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-09 03:22:16 -0400 |
commit | 5180da410db6369d1f95c9014da1c9bc33fb043e (patch) | |
tree | 1d92975710b33a90f77f39d0ad33669329dea949 /arch/x86/mm | |
parent | b1a86e15dc0304366f50ba1720834bc419c801b1 (diff) |
x86, pat: separate the pfn attribute tracking for remap_pfn_range and vm_insert_pfn
With PAT enabled, vm_insert_pfn() looks up the existing pfn memory
attribute and uses it. Expectation is that the driver reserves the
memory attributes for the pfn before calling vm_insert_pfn().
remap_pfn_range() (when called for the whole vma) will setup a new
attribute (based on the prot argument) for the specified pfn range.
This addresses the legacy usage which typically calls remap_pfn_range()
with a desired memory attribute. For ranges smaller than the vma size
(which is typically not the case), remap_pfn_range() will use the
existing memory attribute for the pfn range.
Expose two different API's for these different behaviors.
track_pfn_insert() for tracking the pfn attribute set by vm_insert_pfn()
and track_pfn_remap() for the remap_pfn_range().
This cleanup also prepares the ground for the track/untrack pfn vma
routines to take over the ownership of setting PAT specific vm_flag in
the 'vma'.
[khlebnikov@openvz.org: Clear checks in track_pfn_remap()]
[akpm@linux-foundation.org: tweak a few comments]
Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
Signed-off-by: Konstantin Khlebnikov <khlebnikov@openvz.org>
Cc: Venkatesh Pallipadi <venki@google.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Nick Piggin <npiggin@kernel.dk>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: Carsten Otte <cotte@de.ibm.com>
Cc: Chris Metcalf <cmetcalf@tilera.com>
Cc: Cyrill Gorcunov <gorcunov@openvz.org>
Cc: Eric Paris <eparis@redhat.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: James Morris <james.l.morris@oracle.com>
Cc: Jason Baron <jbaron@redhat.com>
Cc: Kentaro Takeda <takedakn@nttdata.co.jp>
Cc: Konstantin Khlebnikov <khlebnikov@openvz.org>
Cc: Matt Helsley <matthltc@us.ibm.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Robert Richter <robert.richter@amd.com>
Cc: Suresh Siddha <suresh.b.siddha@intel.com>
Cc: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/x86/mm')
-rw-r--r-- | arch/x86/mm/pat.c | 47 |
1 files changed, 36 insertions, 11 deletions
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index de36c886cd38..74a702674e86 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c | |||
@@ -664,13 +664,13 @@ static void free_pfn_range(u64 paddr, unsigned long size) | |||
664 | } | 664 | } |
665 | 665 | ||
666 | /* | 666 | /* |
667 | * track_pfn_vma_copy is called when vma that is covering the pfnmap gets | 667 | * track_pfn_copy is called when vma that is covering the pfnmap gets |
668 | * copied through copy_page_range(). | 668 | * copied through copy_page_range(). |
669 | * | 669 | * |
670 | * If the vma has a linear pfn mapping for the entire range, we get the prot | 670 | * If the vma has a linear pfn mapping for the entire range, we get the prot |
671 | * from pte and reserve the entire vma range with single reserve_pfn_range call. | 671 | * from pte and reserve the entire vma range with single reserve_pfn_range call. |
672 | */ | 672 | */ |
673 | int track_pfn_vma_copy(struct vm_area_struct *vma) | 673 | int track_pfn_copy(struct vm_area_struct *vma) |
674 | { | 674 | { |
675 | resource_size_t paddr; | 675 | resource_size_t paddr; |
676 | unsigned long prot; | 676 | unsigned long prot; |
@@ -694,15 +694,12 @@ int track_pfn_vma_copy(struct vm_area_struct *vma) | |||
694 | } | 694 | } |
695 | 695 | ||
696 | /* | 696 | /* |
697 | * track_pfn_vma_new is called when a _new_ pfn mapping is being established | ||
698 | * for physical range indicated by pfn and size. | ||
699 | * | ||
700 | * prot is passed in as a parameter for the new mapping. If the vma has a | 697 | * prot is passed in as a parameter for the new mapping. If the vma has a |
701 | * linear pfn mapping for the entire range reserve the entire vma range with | 698 | * linear pfn mapping for the entire range reserve the entire vma range with |
702 | * single reserve_pfn_range call. | 699 | * single reserve_pfn_range call. |
703 | */ | 700 | */ |
704 | int track_pfn_vma_new(struct vm_area_struct *vma, pgprot_t *prot, | 701 | int track_pfn_remap(struct vm_area_struct *vma, pgprot_t *prot, |
705 | unsigned long pfn, unsigned long size) | 702 | unsigned long pfn, unsigned long size) |
706 | { | 703 | { |
707 | resource_size_t paddr = (resource_size_t)pfn << PAGE_SHIFT; | 704 | resource_size_t paddr = (resource_size_t)pfn << PAGE_SHIFT; |
708 | unsigned long flags; | 705 | unsigned long flags; |
@@ -714,8 +711,36 @@ int track_pfn_vma_new(struct vm_area_struct *vma, pgprot_t *prot, | |||
714 | if (!pat_enabled) | 711 | if (!pat_enabled) |
715 | return 0; | 712 | return 0; |
716 | 713 | ||
717 | /* for vm_insert_pfn and friends, we set prot based on lookup */ | 714 | /* |
715 | * For anything smaller than the vma size we set prot based on the | ||
716 | * lookup. | ||
717 | */ | ||
718 | flags = lookup_memtype(paddr); | 718 | flags = lookup_memtype(paddr); |
719 | |||
720 | /* Check memtype for the remaining pages */ | ||
721 | while (size > PAGE_SIZE) { | ||
722 | size -= PAGE_SIZE; | ||
723 | paddr += PAGE_SIZE; | ||
724 | if (flags != lookup_memtype(paddr)) | ||
725 | return -EINVAL; | ||
726 | } | ||
727 | |||
728 | *prot = __pgprot((pgprot_val(vma->vm_page_prot) & (~_PAGE_CACHE_MASK)) | | ||
729 | flags); | ||
730 | |||
731 | return 0; | ||
732 | } | ||
733 | |||
734 | int track_pfn_insert(struct vm_area_struct *vma, pgprot_t *prot, | ||
735 | unsigned long pfn) | ||
736 | { | ||
737 | unsigned long flags; | ||
738 | |||
739 | if (!pat_enabled) | ||
740 | return 0; | ||
741 | |||
742 | /* Set prot based on lookup */ | ||
743 | flags = lookup_memtype((resource_size_t)pfn << PAGE_SHIFT); | ||
719 | *prot = __pgprot((pgprot_val(vma->vm_page_prot) & (~_PAGE_CACHE_MASK)) | | 744 | *prot = __pgprot((pgprot_val(vma->vm_page_prot) & (~_PAGE_CACHE_MASK)) | |
720 | flags); | 745 | flags); |
721 | 746 | ||
@@ -723,12 +748,12 @@ int track_pfn_vma_new(struct vm_area_struct *vma, pgprot_t *prot, | |||
723 | } | 748 | } |
724 | 749 | ||
725 | /* | 750 | /* |
726 | * untrack_pfn_vma is called while unmapping a pfnmap for a region. | 751 | * untrack_pfn is called while unmapping a pfnmap for a region. |
727 | * untrack can be called for a specific region indicated by pfn and size or | 752 | * untrack can be called for a specific region indicated by pfn and size or |
728 | * can be for the entire vma (in which case pfn, size are zero). | 753 | * can be for the entire vma (in which case pfn, size are zero). |
729 | */ | 754 | */ |
730 | void untrack_pfn_vma(struct vm_area_struct *vma, unsigned long pfn, | 755 | void untrack_pfn(struct vm_area_struct *vma, unsigned long pfn, |
731 | unsigned long size) | 756 | unsigned long size) |
732 | { | 757 | { |
733 | resource_size_t paddr; | 758 | resource_size_t paddr; |
734 | unsigned long prot; | 759 | unsigned long prot; |