diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-04-17 12:56:11 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-04-17 12:56:11 -0400 |
commit | b9836e08375d86834edcde45e3628e63db8b9624 (patch) | |
tree | a173fe2ab6fbc3e5b44f19faecd50a65efa9cfdd /arch | |
parent | 6566abdbd0566fc1b5950c9f87ef57c7443d6fa8 (diff) | |
parent | 0917798d82212f884fff650e7e520de3b438f947 (diff) |
Merge branch 'x86-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'x86-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
x86: fix microcode driver newly spewing warnings
x86, PAT: Remove page granularity tracking for vm_insert_pfn maps
x86: disable X86_PTRACE_BTS for now
x86, documentation: kernel-parameters replace X86-32,X86-64 with X86
x86: pci-swiotlb.c swiotlb_dma_ops should be static
x86, PAT: Remove duplicate memtype reserve in devmem mmap
x86, PAT: Consolidate code in pat_x_mtrr_type() and reserve_memtype()
x86, PAT: Changing memtype to WC ensuring no WB alias
x86, PAT: Handle faults cleanly in set_memory_ APIs
x86, PAT: Change order of cpa and free in set_memory_wb
x86, CPA: Change idmap attribute before ioremap attribute setup
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/Kconfig.cpu | 1 | ||||
-rw-r--r-- | arch/x86/include/asm/pat.h | 4 | ||||
-rw-r--r-- | arch/x86/kernel/microcode_core.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/pci-swiotlb.c | 2 | ||||
-rw-r--r-- | arch/x86/mm/ioremap.c | 10 | ||||
-rw-r--r-- | arch/x86/mm/pageattr.c | 127 | ||||
-rw-r--r-- | arch/x86/mm/pat.c | 189 |
7 files changed, 117 insertions, 218 deletions
diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu index 924e156a85ab..8130334329c0 100644 --- a/arch/x86/Kconfig.cpu +++ b/arch/x86/Kconfig.cpu | |||
@@ -506,6 +506,7 @@ config X86_PTRACE_BTS | |||
506 | bool "Branch Trace Store" | 506 | bool "Branch Trace Store" |
507 | default y | 507 | default y |
508 | depends on X86_DEBUGCTLMSR | 508 | depends on X86_DEBUGCTLMSR |
509 | depends on BROKEN | ||
509 | ---help--- | 510 | ---help--- |
510 | This adds a ptrace interface to the hardware's branch trace store. | 511 | This adds a ptrace interface to the hardware's branch trace store. |
511 | 512 | ||
diff --git a/arch/x86/include/asm/pat.h b/arch/x86/include/asm/pat.h index 2cd07b9422f4..7af14e512f97 100644 --- a/arch/x86/include/asm/pat.h +++ b/arch/x86/include/asm/pat.h | |||
@@ -18,9 +18,5 @@ extern int free_memtype(u64 start, u64 end); | |||
18 | 18 | ||
19 | extern int kernel_map_sync_memtype(u64 base, unsigned long size, | 19 | extern int kernel_map_sync_memtype(u64 base, unsigned long size, |
20 | unsigned long flag); | 20 | unsigned long flag); |
21 | extern void map_devmem(unsigned long pfn, unsigned long size, | ||
22 | struct pgprot vma_prot); | ||
23 | extern void unmap_devmem(unsigned long pfn, unsigned long size, | ||
24 | struct pgprot vma_prot); | ||
25 | 21 | ||
26 | #endif /* _ASM_X86_PAT_H */ | 22 | #endif /* _ASM_X86_PAT_H */ |
diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c index 2e0eb4140951..98c470c069d1 100644 --- a/arch/x86/kernel/microcode_core.c +++ b/arch/x86/kernel/microcode_core.c | |||
@@ -380,8 +380,6 @@ static int mc_sysdev_add(struct sys_device *sys_dev) | |||
380 | return err; | 380 | return err; |
381 | 381 | ||
382 | err = microcode_init_cpu(cpu); | 382 | err = microcode_init_cpu(cpu); |
383 | if (err) | ||
384 | sysfs_remove_group(&sys_dev->kobj, &mc_attr_group); | ||
385 | 383 | ||
386 | return err; | 384 | return err; |
387 | } | 385 | } |
diff --git a/arch/x86/kernel/pci-swiotlb.c b/arch/x86/kernel/pci-swiotlb.c index 34f12e9996ed..221a3853e268 100644 --- a/arch/x86/kernel/pci-swiotlb.c +++ b/arch/x86/kernel/pci-swiotlb.c | |||
@@ -50,7 +50,7 @@ static void *x86_swiotlb_alloc_coherent(struct device *hwdev, size_t size, | |||
50 | return swiotlb_alloc_coherent(hwdev, size, dma_handle, flags); | 50 | return swiotlb_alloc_coherent(hwdev, size, dma_handle, flags); |
51 | } | 51 | } |
52 | 52 | ||
53 | struct dma_map_ops swiotlb_dma_ops = { | 53 | static struct dma_map_ops swiotlb_dma_ops = { |
54 | .mapping_error = swiotlb_dma_mapping_error, | 54 | .mapping_error = swiotlb_dma_mapping_error, |
55 | .alloc_coherent = x86_swiotlb_alloc_coherent, | 55 | .alloc_coherent = x86_swiotlb_alloc_coherent, |
56 | .free_coherent = swiotlb_free_coherent, | 56 | .free_coherent = swiotlb_free_coherent, |
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c index 09daebfdb11c..8a450930834f 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c | |||
@@ -280,15 +280,16 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr, | |||
280 | return NULL; | 280 | return NULL; |
281 | area->phys_addr = phys_addr; | 281 | area->phys_addr = phys_addr; |
282 | vaddr = (unsigned long) area->addr; | 282 | vaddr = (unsigned long) area->addr; |
283 | if (ioremap_page_range(vaddr, vaddr + size, phys_addr, prot)) { | 283 | |
284 | if (kernel_map_sync_memtype(phys_addr, size, prot_val)) { | ||
284 | free_memtype(phys_addr, phys_addr + size); | 285 | free_memtype(phys_addr, phys_addr + size); |
285 | free_vm_area(area); | 286 | free_vm_area(area); |
286 | return NULL; | 287 | return NULL; |
287 | } | 288 | } |
288 | 289 | ||
289 | if (ioremap_change_attr(vaddr, size, prot_val) < 0) { | 290 | if (ioremap_page_range(vaddr, vaddr + size, phys_addr, prot)) { |
290 | free_memtype(phys_addr, phys_addr + size); | 291 | free_memtype(phys_addr, phys_addr + size); |
291 | vunmap(area->addr); | 292 | free_vm_area(area); |
292 | return NULL; | 293 | return NULL; |
293 | } | 294 | } |
294 | 295 | ||
@@ -374,7 +375,8 @@ static void __iomem *ioremap_default(resource_size_t phys_addr, | |||
374 | * - UC_MINUS for non-WB-able memory with no other conflicting mappings | 375 | * - UC_MINUS for non-WB-able memory with no other conflicting mappings |
375 | * - Inherit from confliting mappings otherwise | 376 | * - Inherit from confliting mappings otherwise |
376 | */ | 377 | */ |
377 | err = reserve_memtype(phys_addr, phys_addr + size, -1, &flags); | 378 | err = reserve_memtype(phys_addr, phys_addr + size, |
379 | _PAGE_CACHE_WB, &flags); | ||
378 | if (err < 0) | 380 | if (err < 0) |
379 | return NULL; | 381 | return NULL; |
380 | 382 | ||
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index d71e1b636ce6..797f9f107cb6 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c | |||
@@ -945,71 +945,94 @@ int _set_memory_uc(unsigned long addr, int numpages) | |||
945 | 945 | ||
946 | int set_memory_uc(unsigned long addr, int numpages) | 946 | int set_memory_uc(unsigned long addr, int numpages) |
947 | { | 947 | { |
948 | int ret; | ||
949 | |||
948 | /* | 950 | /* |
949 | * for now UC MINUS. see comments in ioremap_nocache() | 951 | * for now UC MINUS. see comments in ioremap_nocache() |
950 | */ | 952 | */ |
951 | if (reserve_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE, | 953 | ret = reserve_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE, |
952 | _PAGE_CACHE_UC_MINUS, NULL)) | 954 | _PAGE_CACHE_UC_MINUS, NULL); |
953 | return -EINVAL; | 955 | if (ret) |
956 | goto out_err; | ||
957 | |||
958 | ret = _set_memory_uc(addr, numpages); | ||
959 | if (ret) | ||
960 | goto out_free; | ||
954 | 961 | ||
955 | return _set_memory_uc(addr, numpages); | 962 | return 0; |
963 | |||
964 | out_free: | ||
965 | free_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE); | ||
966 | out_err: | ||
967 | return ret; | ||
956 | } | 968 | } |
957 | EXPORT_SYMBOL(set_memory_uc); | 969 | EXPORT_SYMBOL(set_memory_uc); |
958 | 970 | ||
959 | int set_memory_array_uc(unsigned long *addr, int addrinarray) | 971 | int set_memory_array_uc(unsigned long *addr, int addrinarray) |
960 | { | 972 | { |
961 | unsigned long start; | 973 | int i, j; |
962 | unsigned long end; | 974 | int ret; |
963 | int i; | 975 | |
964 | /* | 976 | /* |
965 | * for now UC MINUS. see comments in ioremap_nocache() | 977 | * for now UC MINUS. see comments in ioremap_nocache() |
966 | */ | 978 | */ |
967 | for (i = 0; i < addrinarray; i++) { | 979 | for (i = 0; i < addrinarray; i++) { |
968 | start = __pa(addr[i]); | 980 | ret = reserve_memtype(__pa(addr[i]), __pa(addr[i]) + PAGE_SIZE, |
969 | for (end = start + PAGE_SIZE; i < addrinarray - 1; end += PAGE_SIZE) { | 981 | _PAGE_CACHE_UC_MINUS, NULL); |
970 | if (end != __pa(addr[i + 1])) | 982 | if (ret) |
971 | break; | 983 | goto out_free; |
972 | i++; | ||
973 | } | ||
974 | if (reserve_memtype(start, end, _PAGE_CACHE_UC_MINUS, NULL)) | ||
975 | goto out; | ||
976 | } | 984 | } |
977 | 985 | ||
978 | return change_page_attr_set(addr, addrinarray, | 986 | ret = change_page_attr_set(addr, addrinarray, |
979 | __pgprot(_PAGE_CACHE_UC_MINUS), 1); | 987 | __pgprot(_PAGE_CACHE_UC_MINUS), 1); |
980 | out: | 988 | if (ret) |
981 | for (i = 0; i < addrinarray; i++) { | 989 | goto out_free; |
982 | unsigned long tmp = __pa(addr[i]); | 990 | |
983 | 991 | return 0; | |
984 | if (tmp == start) | 992 | |
985 | break; | 993 | out_free: |
986 | for (end = tmp + PAGE_SIZE; i < addrinarray - 1; end += PAGE_SIZE) { | 994 | for (j = 0; j < i; j++) |
987 | if (end != __pa(addr[i + 1])) | 995 | free_memtype(__pa(addr[j]), __pa(addr[j]) + PAGE_SIZE); |
988 | break; | 996 | |
989 | i++; | 997 | return ret; |
990 | } | ||
991 | free_memtype(tmp, end); | ||
992 | } | ||
993 | return -EINVAL; | ||
994 | } | 998 | } |
995 | EXPORT_SYMBOL(set_memory_array_uc); | 999 | EXPORT_SYMBOL(set_memory_array_uc); |
996 | 1000 | ||
997 | int _set_memory_wc(unsigned long addr, int numpages) | 1001 | int _set_memory_wc(unsigned long addr, int numpages) |
998 | { | 1002 | { |
999 | return change_page_attr_set(&addr, numpages, | 1003 | int ret; |
1004 | ret = change_page_attr_set(&addr, numpages, | ||
1005 | __pgprot(_PAGE_CACHE_UC_MINUS), 0); | ||
1006 | |||
1007 | if (!ret) { | ||
1008 | ret = change_page_attr_set(&addr, numpages, | ||
1000 | __pgprot(_PAGE_CACHE_WC), 0); | 1009 | __pgprot(_PAGE_CACHE_WC), 0); |
1010 | } | ||
1011 | return ret; | ||
1001 | } | 1012 | } |
1002 | 1013 | ||
1003 | int set_memory_wc(unsigned long addr, int numpages) | 1014 | int set_memory_wc(unsigned long addr, int numpages) |
1004 | { | 1015 | { |
1016 | int ret; | ||
1017 | |||
1005 | if (!pat_enabled) | 1018 | if (!pat_enabled) |
1006 | return set_memory_uc(addr, numpages); | 1019 | return set_memory_uc(addr, numpages); |
1007 | 1020 | ||
1008 | if (reserve_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE, | 1021 | ret = reserve_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE, |
1009 | _PAGE_CACHE_WC, NULL)) | 1022 | _PAGE_CACHE_WC, NULL); |
1010 | return -EINVAL; | 1023 | if (ret) |
1024 | goto out_err; | ||
1025 | |||
1026 | ret = _set_memory_wc(addr, numpages); | ||
1027 | if (ret) | ||
1028 | goto out_free; | ||
1029 | |||
1030 | return 0; | ||
1011 | 1031 | ||
1012 | return _set_memory_wc(addr, numpages); | 1032 | out_free: |
1033 | free_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE); | ||
1034 | out_err: | ||
1035 | return ret; | ||
1013 | } | 1036 | } |
1014 | EXPORT_SYMBOL(set_memory_wc); | 1037 | EXPORT_SYMBOL(set_memory_wc); |
1015 | 1038 | ||
@@ -1021,29 +1044,31 @@ int _set_memory_wb(unsigned long addr, int numpages) | |||
1021 | 1044 | ||
1022 | int set_memory_wb(unsigned long addr, int numpages) | 1045 | int set_memory_wb(unsigned long addr, int numpages) |
1023 | { | 1046 | { |
1024 | free_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE); | 1047 | int ret; |
1048 | |||
1049 | ret = _set_memory_wb(addr, numpages); | ||
1050 | if (ret) | ||
1051 | return ret; | ||
1025 | 1052 | ||
1026 | return _set_memory_wb(addr, numpages); | 1053 | free_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE); |
1054 | return 0; | ||
1027 | } | 1055 | } |
1028 | EXPORT_SYMBOL(set_memory_wb); | 1056 | EXPORT_SYMBOL(set_memory_wb); |
1029 | 1057 | ||
1030 | int set_memory_array_wb(unsigned long *addr, int addrinarray) | 1058 | int set_memory_array_wb(unsigned long *addr, int addrinarray) |
1031 | { | 1059 | { |
1032 | int i; | 1060 | int i; |
1061 | int ret; | ||
1033 | 1062 | ||
1034 | for (i = 0; i < addrinarray; i++) { | 1063 | ret = change_page_attr_clear(addr, addrinarray, |
1035 | unsigned long start = __pa(addr[i]); | ||
1036 | unsigned long end; | ||
1037 | |||
1038 | for (end = start + PAGE_SIZE; i < addrinarray - 1; end += PAGE_SIZE) { | ||
1039 | if (end != __pa(addr[i + 1])) | ||
1040 | break; | ||
1041 | i++; | ||
1042 | } | ||
1043 | free_memtype(start, end); | ||
1044 | } | ||
1045 | return change_page_attr_clear(addr, addrinarray, | ||
1046 | __pgprot(_PAGE_CACHE_MASK), 1); | 1064 | __pgprot(_PAGE_CACHE_MASK), 1); |
1065 | if (ret) | ||
1066 | return ret; | ||
1067 | |||
1068 | for (i = 0; i < addrinarray; i++) | ||
1069 | free_memtype(__pa(addr[i]), __pa(addr[i]) + PAGE_SIZE); | ||
1070 | |||
1071 | return 0; | ||
1047 | } | 1072 | } |
1048 | EXPORT_SYMBOL(set_memory_array_wb); | 1073 | EXPORT_SYMBOL(set_memory_array_wb); |
1049 | 1074 | ||
@@ -1136,6 +1161,8 @@ int set_pages_array_wb(struct page **pages, int addrinarray) | |||
1136 | 1161 | ||
1137 | retval = cpa_clear_pages_array(pages, addrinarray, | 1162 | retval = cpa_clear_pages_array(pages, addrinarray, |
1138 | __pgprot(_PAGE_CACHE_MASK)); | 1163 | __pgprot(_PAGE_CACHE_MASK)); |
1164 | if (retval) | ||
1165 | return retval; | ||
1139 | 1166 | ||
1140 | for (i = 0; i < addrinarray; i++) { | 1167 | for (i = 0; i < addrinarray; i++) { |
1141 | start = (unsigned long)page_address(pages[i]); | 1168 | start = (unsigned long)page_address(pages[i]); |
@@ -1143,7 +1170,7 @@ int set_pages_array_wb(struct page **pages, int addrinarray) | |||
1143 | free_memtype(start, end); | 1170 | free_memtype(start, end); |
1144 | } | 1171 | } |
1145 | 1172 | ||
1146 | return retval; | 1173 | return 0; |
1147 | } | 1174 | } |
1148 | EXPORT_SYMBOL(set_pages_array_wb); | 1175 | EXPORT_SYMBOL(set_pages_array_wb); |
1149 | 1176 | ||
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index c009a241d562..e6718bb28065 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c | |||
@@ -182,10 +182,10 @@ static unsigned long pat_x_mtrr_type(u64 start, u64 end, unsigned long req_type) | |||
182 | u8 mtrr_type; | 182 | u8 mtrr_type; |
183 | 183 | ||
184 | mtrr_type = mtrr_type_lookup(start, end); | 184 | mtrr_type = mtrr_type_lookup(start, end); |
185 | if (mtrr_type == MTRR_TYPE_UNCACHABLE) | 185 | if (mtrr_type != MTRR_TYPE_WRBACK) |
186 | return _PAGE_CACHE_UC; | 186 | return _PAGE_CACHE_UC_MINUS; |
187 | if (mtrr_type == MTRR_TYPE_WRCOMB) | 187 | |
188 | return _PAGE_CACHE_WC; | 188 | return _PAGE_CACHE_WB; |
189 | } | 189 | } |
190 | 190 | ||
191 | return req_type; | 191 | return req_type; |
@@ -352,23 +352,13 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, | |||
352 | return 0; | 352 | return 0; |
353 | } | 353 | } |
354 | 354 | ||
355 | if (req_type == -1) { | 355 | /* |
356 | /* | 356 | * Call mtrr_lookup to get the type hint. This is an |
357 | * Call mtrr_lookup to get the type hint. This is an | 357 | * optimization for /dev/mem mmap'ers into WB memory (BIOS |
358 | * optimization for /dev/mem mmap'ers into WB memory (BIOS | 358 | * tools and ACPI tools). Use WB request for WB memory and use |
359 | * tools and ACPI tools). Use WB request for WB memory and use | 359 | * UC_MINUS otherwise. |
360 | * UC_MINUS otherwise. | 360 | */ |
361 | */ | 361 | actual_type = pat_x_mtrr_type(start, end, req_type & _PAGE_CACHE_MASK); |
362 | u8 mtrr_type = mtrr_type_lookup(start, end); | ||
363 | |||
364 | if (mtrr_type == MTRR_TYPE_WRBACK) | ||
365 | actual_type = _PAGE_CACHE_WB; | ||
366 | else | ||
367 | actual_type = _PAGE_CACHE_UC_MINUS; | ||
368 | } else { | ||
369 | actual_type = pat_x_mtrr_type(start, end, | ||
370 | req_type & _PAGE_CACHE_MASK); | ||
371 | } | ||
372 | 362 | ||
373 | if (new_type) | 363 | if (new_type) |
374 | *new_type = actual_type; | 364 | *new_type = actual_type; |
@@ -546,9 +536,7 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size) | |||
546 | int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn, | 536 | int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn, |
547 | unsigned long size, pgprot_t *vma_prot) | 537 | unsigned long size, pgprot_t *vma_prot) |
548 | { | 538 | { |
549 | u64 offset = ((u64) pfn) << PAGE_SHIFT; | 539 | unsigned long flags = _PAGE_CACHE_WB; |
550 | unsigned long flags = -1; | ||
551 | int retval; | ||
552 | 540 | ||
553 | if (!range_is_allowed(pfn, size)) | 541 | if (!range_is_allowed(pfn, size)) |
554 | return 0; | 542 | return 0; |
@@ -576,64 +564,11 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn, | |||
576 | } | 564 | } |
577 | #endif | 565 | #endif |
578 | 566 | ||
579 | /* | ||
580 | * With O_SYNC, we can only take UC_MINUS mapping. Fail if we cannot. | ||
581 | * | ||
582 | * Without O_SYNC, we want to get | ||
583 | * - WB for WB-able memory and no other conflicting mappings | ||
584 | * - UC_MINUS for non-WB-able memory with no other conflicting mappings | ||
585 | * - Inherit from confliting mappings otherwise | ||
586 | */ | ||
587 | if (flags != -1) { | ||
588 | retval = reserve_memtype(offset, offset + size, flags, NULL); | ||
589 | } else { | ||
590 | retval = reserve_memtype(offset, offset + size, -1, &flags); | ||
591 | } | ||
592 | |||
593 | if (retval < 0) | ||
594 | return 0; | ||
595 | |||
596 | if (((pfn < max_low_pfn_mapped) || | ||
597 | (pfn >= (1UL<<(32 - PAGE_SHIFT)) && pfn < max_pfn_mapped)) && | ||
598 | ioremap_change_attr((unsigned long)__va(offset), size, flags) < 0) { | ||
599 | free_memtype(offset, offset + size); | ||
600 | printk(KERN_INFO | ||
601 | "%s:%d /dev/mem ioremap_change_attr failed %s for %Lx-%Lx\n", | ||
602 | current->comm, current->pid, | ||
603 | cattr_name(flags), | ||
604 | offset, (unsigned long long)(offset + size)); | ||
605 | return 0; | ||
606 | } | ||
607 | |||
608 | *vma_prot = __pgprot((pgprot_val(*vma_prot) & ~_PAGE_CACHE_MASK) | | 567 | *vma_prot = __pgprot((pgprot_val(*vma_prot) & ~_PAGE_CACHE_MASK) | |
609 | flags); | 568 | flags); |
610 | return 1; | 569 | return 1; |
611 | } | 570 | } |
612 | 571 | ||
613 | void map_devmem(unsigned long pfn, unsigned long size, pgprot_t vma_prot) | ||
614 | { | ||
615 | unsigned long want_flags = (pgprot_val(vma_prot) & _PAGE_CACHE_MASK); | ||
616 | u64 addr = (u64)pfn << PAGE_SHIFT; | ||
617 | unsigned long flags; | ||
618 | |||
619 | reserve_memtype(addr, addr + size, want_flags, &flags); | ||
620 | if (flags != want_flags) { | ||
621 | printk(KERN_INFO | ||
622 | "%s:%d /dev/mem expected mapping type %s for %Lx-%Lx, got %s\n", | ||
623 | current->comm, current->pid, | ||
624 | cattr_name(want_flags), | ||
625 | addr, (unsigned long long)(addr + size), | ||
626 | cattr_name(flags)); | ||
627 | } | ||
628 | } | ||
629 | |||
630 | void unmap_devmem(unsigned long pfn, unsigned long size, pgprot_t vma_prot) | ||
631 | { | ||
632 | u64 addr = (u64)pfn << PAGE_SHIFT; | ||
633 | |||
634 | free_memtype(addr, addr + size); | ||
635 | } | ||
636 | |||
637 | /* | 572 | /* |
638 | * Change the memory type for the physial address range in kernel identity | 573 | * Change the memory type for the physial address range in kernel identity |
639 | * mapping space if that range is a part of identity map. | 574 | * mapping space if that range is a part of identity map. |
@@ -671,8 +606,8 @@ static int reserve_pfn_range(u64 paddr, unsigned long size, pgprot_t *vma_prot, | |||
671 | { | 606 | { |
672 | int is_ram = 0; | 607 | int is_ram = 0; |
673 | int ret; | 608 | int ret; |
674 | unsigned long flags; | ||
675 | unsigned long want_flags = (pgprot_val(*vma_prot) & _PAGE_CACHE_MASK); | 609 | unsigned long want_flags = (pgprot_val(*vma_prot) & _PAGE_CACHE_MASK); |
610 | unsigned long flags = want_flags; | ||
676 | 611 | ||
677 | is_ram = pat_pagerange_is_ram(paddr, paddr + size); | 612 | is_ram = pat_pagerange_is_ram(paddr, paddr + size); |
678 | 613 | ||
@@ -734,29 +669,28 @@ static void free_pfn_range(u64 paddr, unsigned long size) | |||
734 | * | 669 | * |
735 | * 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 |
736 | * 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. |
737 | * Otherwise, we reserve the entire vma range, my ging through the PTEs page | ||
738 | * by page to get physical address and protection. | ||
739 | */ | 672 | */ |
740 | int track_pfn_vma_copy(struct vm_area_struct *vma) | 673 | int track_pfn_vma_copy(struct vm_area_struct *vma) |
741 | { | 674 | { |
742 | int retval = 0; | ||
743 | unsigned long i, j; | ||
744 | resource_size_t paddr; | 675 | resource_size_t paddr; |
745 | unsigned long prot; | 676 | unsigned long prot; |
746 | unsigned long vma_start = vma->vm_start; | 677 | unsigned long vma_size = vma->vm_end - vma->vm_start; |
747 | unsigned long vma_end = vma->vm_end; | ||
748 | unsigned long vma_size = vma_end - vma_start; | ||
749 | pgprot_t pgprot; | 678 | pgprot_t pgprot; |
750 | 679 | ||
751 | if (!pat_enabled) | 680 | if (!pat_enabled) |
752 | return 0; | 681 | return 0; |
753 | 682 | ||
683 | /* | ||
684 | * For now, only handle remap_pfn_range() vmas where | ||
685 | * is_linear_pfn_mapping() == TRUE. Handling of | ||
686 | * vm_insert_pfn() is TBD. | ||
687 | */ | ||
754 | if (is_linear_pfn_mapping(vma)) { | 688 | if (is_linear_pfn_mapping(vma)) { |
755 | /* | 689 | /* |
756 | * reserve the whole chunk covered by vma. We need the | 690 | * reserve the whole chunk covered by vma. We need the |
757 | * starting address and protection from pte. | 691 | * starting address and protection from pte. |
758 | */ | 692 | */ |
759 | if (follow_phys(vma, vma_start, 0, &prot, &paddr)) { | 693 | if (follow_phys(vma, vma->vm_start, 0, &prot, &paddr)) { |
760 | WARN_ON_ONCE(1); | 694 | WARN_ON_ONCE(1); |
761 | return -EINVAL; | 695 | return -EINVAL; |
762 | } | 696 | } |
@@ -764,28 +698,7 @@ int track_pfn_vma_copy(struct vm_area_struct *vma) | |||
764 | return reserve_pfn_range(paddr, vma_size, &pgprot, 1); | 698 | return reserve_pfn_range(paddr, vma_size, &pgprot, 1); |
765 | } | 699 | } |
766 | 700 | ||
767 | /* reserve entire vma page by page, using pfn and prot from pte */ | ||
768 | for (i = 0; i < vma_size; i += PAGE_SIZE) { | ||
769 | if (follow_phys(vma, vma_start + i, 0, &prot, &paddr)) | ||
770 | continue; | ||
771 | |||
772 | pgprot = __pgprot(prot); | ||
773 | retval = reserve_pfn_range(paddr, PAGE_SIZE, &pgprot, 1); | ||
774 | if (retval) | ||
775 | goto cleanup_ret; | ||
776 | } | ||
777 | return 0; | 701 | return 0; |
778 | |||
779 | cleanup_ret: | ||
780 | /* Reserve error: Cleanup partial reservation and return error */ | ||
781 | for (j = 0; j < i; j += PAGE_SIZE) { | ||
782 | if (follow_phys(vma, vma_start + j, 0, &prot, &paddr)) | ||
783 | continue; | ||
784 | |||
785 | free_pfn_range(paddr, PAGE_SIZE); | ||
786 | } | ||
787 | |||
788 | return retval; | ||
789 | } | 702 | } |
790 | 703 | ||
791 | /* | 704 | /* |
@@ -795,50 +708,28 @@ cleanup_ret: | |||
795 | * prot is passed in as a parameter for the new mapping. If the vma has a | 708 | * prot is passed in as a parameter for the new mapping. If the vma has a |
796 | * linear pfn mapping for the entire range reserve the entire vma range with | 709 | * linear pfn mapping for the entire range reserve the entire vma range with |
797 | * single reserve_pfn_range call. | 710 | * single reserve_pfn_range call. |
798 | * Otherwise, we look t the pfn and size and reserve only the specified range | ||
799 | * page by page. | ||
800 | * | ||
801 | * Note that this function can be called with caller trying to map only a | ||
802 | * subrange/page inside the vma. | ||
803 | */ | 711 | */ |
804 | int track_pfn_vma_new(struct vm_area_struct *vma, pgprot_t *prot, | 712 | int track_pfn_vma_new(struct vm_area_struct *vma, pgprot_t *prot, |
805 | unsigned long pfn, unsigned long size) | 713 | unsigned long pfn, unsigned long size) |
806 | { | 714 | { |
807 | int retval = 0; | ||
808 | unsigned long i, j; | ||
809 | resource_size_t base_paddr; | ||
810 | resource_size_t paddr; | 715 | resource_size_t paddr; |
811 | unsigned long vma_start = vma->vm_start; | 716 | unsigned long vma_size = vma->vm_end - vma->vm_start; |
812 | unsigned long vma_end = vma->vm_end; | ||
813 | unsigned long vma_size = vma_end - vma_start; | ||
814 | 717 | ||
815 | if (!pat_enabled) | 718 | if (!pat_enabled) |
816 | return 0; | 719 | return 0; |
817 | 720 | ||
721 | /* | ||
722 | * For now, only handle remap_pfn_range() vmas where | ||
723 | * is_linear_pfn_mapping() == TRUE. Handling of | ||
724 | * vm_insert_pfn() is TBD. | ||
725 | */ | ||
818 | if (is_linear_pfn_mapping(vma)) { | 726 | if (is_linear_pfn_mapping(vma)) { |
819 | /* reserve the whole chunk starting from vm_pgoff */ | 727 | /* reserve the whole chunk starting from vm_pgoff */ |
820 | paddr = (resource_size_t)vma->vm_pgoff << PAGE_SHIFT; | 728 | paddr = (resource_size_t)vma->vm_pgoff << PAGE_SHIFT; |
821 | return reserve_pfn_range(paddr, vma_size, prot, 0); | 729 | return reserve_pfn_range(paddr, vma_size, prot, 0); |
822 | } | 730 | } |
823 | 731 | ||
824 | /* reserve page by page using pfn and size */ | ||
825 | base_paddr = (resource_size_t)pfn << PAGE_SHIFT; | ||
826 | for (i = 0; i < size; i += PAGE_SIZE) { | ||
827 | paddr = base_paddr + i; | ||
828 | retval = reserve_pfn_range(paddr, PAGE_SIZE, prot, 0); | ||
829 | if (retval) | ||
830 | goto cleanup_ret; | ||
831 | } | ||
832 | return 0; | 732 | return 0; |
833 | |||
834 | cleanup_ret: | ||
835 | /* Reserve error: Cleanup partial reservation and return error */ | ||
836 | for (j = 0; j < i; j += PAGE_SIZE) { | ||
837 | paddr = base_paddr + j; | ||
838 | free_pfn_range(paddr, PAGE_SIZE); | ||
839 | } | ||
840 | |||
841 | return retval; | ||
842 | } | 733 | } |
843 | 734 | ||
844 | /* | 735 | /* |
@@ -849,39 +740,23 @@ cleanup_ret: | |||
849 | void untrack_pfn_vma(struct vm_area_struct *vma, unsigned long pfn, | 740 | void untrack_pfn_vma(struct vm_area_struct *vma, unsigned long pfn, |
850 | unsigned long size) | 741 | unsigned long size) |
851 | { | 742 | { |
852 | unsigned long i; | ||
853 | resource_size_t paddr; | 743 | resource_size_t paddr; |
854 | unsigned long prot; | 744 | unsigned long vma_size = vma->vm_end - vma->vm_start; |
855 | unsigned long vma_start = vma->vm_start; | ||
856 | unsigned long vma_end = vma->vm_end; | ||
857 | unsigned long vma_size = vma_end - vma_start; | ||
858 | 745 | ||
859 | if (!pat_enabled) | 746 | if (!pat_enabled) |
860 | return; | 747 | return; |
861 | 748 | ||
749 | /* | ||
750 | * For now, only handle remap_pfn_range() vmas where | ||
751 | * is_linear_pfn_mapping() == TRUE. Handling of | ||
752 | * vm_insert_pfn() is TBD. | ||
753 | */ | ||
862 | if (is_linear_pfn_mapping(vma)) { | 754 | if (is_linear_pfn_mapping(vma)) { |
863 | /* free the whole chunk starting from vm_pgoff */ | 755 | /* free the whole chunk starting from vm_pgoff */ |
864 | paddr = (resource_size_t)vma->vm_pgoff << PAGE_SHIFT; | 756 | paddr = (resource_size_t)vma->vm_pgoff << PAGE_SHIFT; |
865 | free_pfn_range(paddr, vma_size); | 757 | free_pfn_range(paddr, vma_size); |
866 | return; | 758 | return; |
867 | } | 759 | } |
868 | |||
869 | if (size != 0 && size != vma_size) { | ||
870 | /* free page by page, using pfn and size */ | ||
871 | paddr = (resource_size_t)pfn << PAGE_SHIFT; | ||
872 | for (i = 0; i < size; i += PAGE_SIZE) { | ||
873 | paddr = paddr + i; | ||
874 | free_pfn_range(paddr, PAGE_SIZE); | ||
875 | } | ||
876 | } else { | ||
877 | /* free entire vma, page by page, using the pfn from pte */ | ||
878 | for (i = 0; i < vma_size; i += PAGE_SIZE) { | ||
879 | if (follow_phys(vma, vma_start + i, 0, &prot, &paddr)) | ||
880 | continue; | ||
881 | |||
882 | free_pfn_range(paddr, PAGE_SIZE); | ||
883 | } | ||
884 | } | ||
885 | } | 760 | } |
886 | 761 | ||
887 | pgprot_t pgprot_writecombine(pgprot_t prot) | 762 | pgprot_t pgprot_writecombine(pgprot_t prot) |