diff options
Diffstat (limited to 'arch/x86/mm/pat.c')
-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; |