diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-10-28 11:26:12 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-28 11:26:12 -0400 |
commit | 7a9787e1eba95a166265e6a260cf30af04ef0a99 (patch) | |
tree | e730a4565e0318140d2fbd2f0415d18a339d7336 /arch/x86/mm/ioremap.c | |
parent | 41b9eb264c8407655db57b60b4457fe1b2ec9977 (diff) | |
parent | 0173a3265b228da319ceb9c1ec6a5682fd1b2d92 (diff) |
Merge commit 'v2.6.28-rc2' into x86/pci-ioapic-boot-irq-quirks
Diffstat (limited to 'arch/x86/mm/ioremap.c')
-rw-r--r-- | arch/x86/mm/ioremap.c | 213 |
1 files changed, 172 insertions, 41 deletions
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c index 24c1d3c30186..ae71e11eb3e5 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c | |||
@@ -24,18 +24,47 @@ | |||
24 | 24 | ||
25 | #ifdef CONFIG_X86_64 | 25 | #ifdef CONFIG_X86_64 |
26 | 26 | ||
27 | static inline int phys_addr_valid(unsigned long addr) | ||
28 | { | ||
29 | return addr < (1UL << boot_cpu_data.x86_phys_bits); | ||
30 | } | ||
31 | |||
27 | unsigned long __phys_addr(unsigned long x) | 32 | unsigned long __phys_addr(unsigned long x) |
28 | { | 33 | { |
29 | if (x >= __START_KERNEL_map) | 34 | if (x >= __START_KERNEL_map) { |
30 | return x - __START_KERNEL_map + phys_base; | 35 | x -= __START_KERNEL_map; |
31 | return x - PAGE_OFFSET; | 36 | VIRTUAL_BUG_ON(x >= KERNEL_IMAGE_SIZE); |
37 | x += phys_base; | ||
38 | } else { | ||
39 | VIRTUAL_BUG_ON(x < PAGE_OFFSET); | ||
40 | x -= PAGE_OFFSET; | ||
41 | VIRTUAL_BUG_ON(system_state == SYSTEM_BOOTING ? x > MAXMEM : | ||
42 | !phys_addr_valid(x)); | ||
43 | } | ||
44 | return x; | ||
32 | } | 45 | } |
33 | EXPORT_SYMBOL(__phys_addr); | 46 | EXPORT_SYMBOL(__phys_addr); |
34 | 47 | ||
35 | static inline int phys_addr_valid(unsigned long addr) | 48 | bool __virt_addr_valid(unsigned long x) |
36 | { | 49 | { |
37 | return addr < (1UL << boot_cpu_data.x86_phys_bits); | 50 | if (x >= __START_KERNEL_map) { |
51 | x -= __START_KERNEL_map; | ||
52 | if (x >= KERNEL_IMAGE_SIZE) | ||
53 | return false; | ||
54 | x += phys_base; | ||
55 | } else { | ||
56 | if (x < PAGE_OFFSET) | ||
57 | return false; | ||
58 | x -= PAGE_OFFSET; | ||
59 | if (system_state == SYSTEM_BOOTING ? | ||
60 | x > MAXMEM : !phys_addr_valid(x)) { | ||
61 | return false; | ||
62 | } | ||
63 | } | ||
64 | |||
65 | return pfn_valid(x >> PAGE_SHIFT); | ||
38 | } | 66 | } |
67 | EXPORT_SYMBOL(__virt_addr_valid); | ||
39 | 68 | ||
40 | #else | 69 | #else |
41 | 70 | ||
@@ -44,6 +73,28 @@ static inline int phys_addr_valid(unsigned long addr) | |||
44 | return 1; | 73 | return 1; |
45 | } | 74 | } |
46 | 75 | ||
76 | #ifdef CONFIG_DEBUG_VIRTUAL | ||
77 | unsigned long __phys_addr(unsigned long x) | ||
78 | { | ||
79 | /* VMALLOC_* aren't constants; not available at the boot time */ | ||
80 | VIRTUAL_BUG_ON(x < PAGE_OFFSET); | ||
81 | VIRTUAL_BUG_ON(system_state != SYSTEM_BOOTING && | ||
82 | is_vmalloc_addr((void *) x)); | ||
83 | return x - PAGE_OFFSET; | ||
84 | } | ||
85 | EXPORT_SYMBOL(__phys_addr); | ||
86 | #endif | ||
87 | |||
88 | bool __virt_addr_valid(unsigned long x) | ||
89 | { | ||
90 | if (x < PAGE_OFFSET) | ||
91 | return false; | ||
92 | if (system_state != SYSTEM_BOOTING && is_vmalloc_addr((void *) x)) | ||
93 | return false; | ||
94 | return pfn_valid((x - PAGE_OFFSET) >> PAGE_SHIFT); | ||
95 | } | ||
96 | EXPORT_SYMBOL(__virt_addr_valid); | ||
97 | |||
47 | #endif | 98 | #endif |
48 | 99 | ||
49 | int page_is_ram(unsigned long pagenr) | 100 | int page_is_ram(unsigned long pagenr) |
@@ -83,6 +134,25 @@ int page_is_ram(unsigned long pagenr) | |||
83 | return 0; | 134 | return 0; |
84 | } | 135 | } |
85 | 136 | ||
137 | int pagerange_is_ram(unsigned long start, unsigned long end) | ||
138 | { | ||
139 | int ram_page = 0, not_rampage = 0; | ||
140 | unsigned long page_nr; | ||
141 | |||
142 | for (page_nr = (start >> PAGE_SHIFT); page_nr < (end >> PAGE_SHIFT); | ||
143 | ++page_nr) { | ||
144 | if (page_is_ram(page_nr)) | ||
145 | ram_page = 1; | ||
146 | else | ||
147 | not_rampage = 1; | ||
148 | |||
149 | if (ram_page == not_rampage) | ||
150 | return -1; | ||
151 | } | ||
152 | |||
153 | return ram_page; | ||
154 | } | ||
155 | |||
86 | /* | 156 | /* |
87 | * Fix up the linear direct mapping of the kernel to avoid cache attribute | 157 | * Fix up the linear direct mapping of the kernel to avoid cache attribute |
88 | * conflicts. | 158 | * conflicts. |
@@ -150,6 +220,12 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr, | |||
150 | return (__force void __iomem *)phys_to_virt(phys_addr); | 220 | return (__force void __iomem *)phys_to_virt(phys_addr); |
151 | 221 | ||
152 | /* | 222 | /* |
223 | * Check if the request spans more than any BAR in the iomem resource | ||
224 | * tree. | ||
225 | */ | ||
226 | WARN_ON(iomem_map_sanity_check(phys_addr, size)); | ||
227 | |||
228 | /* | ||
153 | * Don't allow anybody to remap normal RAM that we're using.. | 229 | * Don't allow anybody to remap normal RAM that we're using.. |
154 | */ | 230 | */ |
155 | for (pfn = phys_addr >> PAGE_SHIFT; | 231 | for (pfn = phys_addr >> PAGE_SHIFT; |
@@ -170,7 +246,7 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr, | |||
170 | phys_addr &= PAGE_MASK; | 246 | phys_addr &= PAGE_MASK; |
171 | size = PAGE_ALIGN(last_addr+1) - phys_addr; | 247 | size = PAGE_ALIGN(last_addr+1) - phys_addr; |
172 | 248 | ||
173 | retval = reserve_memtype(phys_addr, phys_addr + size, | 249 | retval = reserve_memtype(phys_addr, (u64)phys_addr + size, |
174 | prot_val, &new_prot_val); | 250 | prot_val, &new_prot_val); |
175 | if (retval) { | 251 | if (retval) { |
176 | pr_debug("Warning: reserve_memtype returned %d\n", retval); | 252 | pr_debug("Warning: reserve_memtype returned %d\n", retval); |
@@ -204,16 +280,16 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr, | |||
204 | switch (prot_val) { | 280 | switch (prot_val) { |
205 | case _PAGE_CACHE_UC: | 281 | case _PAGE_CACHE_UC: |
206 | default: | 282 | default: |
207 | prot = PAGE_KERNEL_NOCACHE; | 283 | prot = PAGE_KERNEL_IO_NOCACHE; |
208 | break; | 284 | break; |
209 | case _PAGE_CACHE_UC_MINUS: | 285 | case _PAGE_CACHE_UC_MINUS: |
210 | prot = PAGE_KERNEL_UC_MINUS; | 286 | prot = PAGE_KERNEL_IO_UC_MINUS; |
211 | break; | 287 | break; |
212 | case _PAGE_CACHE_WC: | 288 | case _PAGE_CACHE_WC: |
213 | prot = PAGE_KERNEL_WC; | 289 | prot = PAGE_KERNEL_IO_WC; |
214 | break; | 290 | break; |
215 | case _PAGE_CACHE_WB: | 291 | case _PAGE_CACHE_WB: |
216 | prot = PAGE_KERNEL; | 292 | prot = PAGE_KERNEL_IO; |
217 | break; | 293 | break; |
218 | } | 294 | } |
219 | 295 | ||
@@ -330,6 +406,14 @@ static void __iomem *ioremap_default(resource_size_t phys_addr, | |||
330 | return (void __iomem *)ret; | 406 | return (void __iomem *)ret; |
331 | } | 407 | } |
332 | 408 | ||
409 | void __iomem *ioremap_prot(resource_size_t phys_addr, unsigned long size, | ||
410 | unsigned long prot_val) | ||
411 | { | ||
412 | return __ioremap_caller(phys_addr, size, (prot_val & _PAGE_CACHE_MASK), | ||
413 | __builtin_return_address(0)); | ||
414 | } | ||
415 | EXPORT_SYMBOL(ioremap_prot); | ||
416 | |||
333 | /** | 417 | /** |
334 | * iounmap - Free a IO remapping | 418 | * iounmap - Free a IO remapping |
335 | * @addr: virtual address from ioremap_* | 419 | * @addr: virtual address from ioremap_* |
@@ -413,7 +497,7 @@ void unxlate_dev_mem_ptr(unsigned long phys, void *addr) | |||
413 | return; | 497 | return; |
414 | } | 498 | } |
415 | 499 | ||
416 | int __initdata early_ioremap_debug; | 500 | static int __initdata early_ioremap_debug; |
417 | 501 | ||
418 | static int __init early_ioremap_debug_setup(char *str) | 502 | static int __init early_ioremap_debug_setup(char *str) |
419 | { | 503 | { |
@@ -522,12 +606,12 @@ static void __init __early_set_fixmap(enum fixed_addresses idx, | |||
522 | } | 606 | } |
523 | 607 | ||
524 | static inline void __init early_set_fixmap(enum fixed_addresses idx, | 608 | static inline void __init early_set_fixmap(enum fixed_addresses idx, |
525 | unsigned long phys) | 609 | unsigned long phys, pgprot_t prot) |
526 | { | 610 | { |
527 | if (after_paging_init) | 611 | if (after_paging_init) |
528 | set_fixmap(idx, phys); | 612 | __set_fixmap(idx, phys, prot); |
529 | else | 613 | else |
530 | __early_set_fixmap(idx, phys, PAGE_KERNEL); | 614 | __early_set_fixmap(idx, phys, prot); |
531 | } | 615 | } |
532 | 616 | ||
533 | static inline void __init early_clear_fixmap(enum fixed_addresses idx) | 617 | static inline void __init early_clear_fixmap(enum fixed_addresses idx) |
@@ -538,37 +622,56 @@ static inline void __init early_clear_fixmap(enum fixed_addresses idx) | |||
538 | __early_set_fixmap(idx, 0, __pgprot(0)); | 622 | __early_set_fixmap(idx, 0, __pgprot(0)); |
539 | } | 623 | } |
540 | 624 | ||
541 | 625 | static void *prev_map[FIX_BTMAPS_SLOTS] __initdata; | |
542 | int __initdata early_ioremap_nested; | 626 | static unsigned long prev_size[FIX_BTMAPS_SLOTS] __initdata; |
543 | |||
544 | static int __init check_early_ioremap_leak(void) | 627 | static int __init check_early_ioremap_leak(void) |
545 | { | 628 | { |
546 | if (!early_ioremap_nested) | 629 | int count = 0; |
547 | return 0; | 630 | int i; |
548 | 631 | ||
549 | printk(KERN_WARNING | 632 | for (i = 0; i < FIX_BTMAPS_SLOTS; i++) |
633 | if (prev_map[i]) | ||
634 | count++; | ||
635 | |||
636 | if (!count) | ||
637 | return 0; | ||
638 | WARN(1, KERN_WARNING | ||
550 | "Debug warning: early ioremap leak of %d areas detected.\n", | 639 | "Debug warning: early ioremap leak of %d areas detected.\n", |
551 | early_ioremap_nested); | 640 | count); |
552 | printk(KERN_WARNING | 641 | printk(KERN_WARNING |
553 | "please boot with early_ioremap_debug and report the dmesg.\n"); | 642 | "please boot with early_ioremap_debug and report the dmesg.\n"); |
554 | WARN_ON(1); | ||
555 | 643 | ||
556 | return 1; | 644 | return 1; |
557 | } | 645 | } |
558 | late_initcall(check_early_ioremap_leak); | 646 | late_initcall(check_early_ioremap_leak); |
559 | 647 | ||
560 | void __init *early_ioremap(unsigned long phys_addr, unsigned long size) | 648 | static void __init *__early_ioremap(unsigned long phys_addr, unsigned long size, pgprot_t prot) |
561 | { | 649 | { |
562 | unsigned long offset, last_addr; | 650 | unsigned long offset, last_addr; |
563 | unsigned int nrpages, nesting; | 651 | unsigned int nrpages; |
564 | enum fixed_addresses idx0, idx; | 652 | enum fixed_addresses idx0, idx; |
653 | int i, slot; | ||
565 | 654 | ||
566 | WARN_ON(system_state != SYSTEM_BOOTING); | 655 | WARN_ON(system_state != SYSTEM_BOOTING); |
567 | 656 | ||
568 | nesting = early_ioremap_nested; | 657 | slot = -1; |
658 | for (i = 0; i < FIX_BTMAPS_SLOTS; i++) { | ||
659 | if (!prev_map[i]) { | ||
660 | slot = i; | ||
661 | break; | ||
662 | } | ||
663 | } | ||
664 | |||
665 | if (slot < 0) { | ||
666 | printk(KERN_INFO "early_iomap(%08lx, %08lx) not found slot\n", | ||
667 | phys_addr, size); | ||
668 | WARN_ON(1); | ||
669 | return NULL; | ||
670 | } | ||
671 | |||
569 | if (early_ioremap_debug) { | 672 | if (early_ioremap_debug) { |
570 | printk(KERN_INFO "early_ioremap(%08lx, %08lx) [%d] => ", | 673 | printk(KERN_INFO "early_ioremap(%08lx, %08lx) [%d] => ", |
571 | phys_addr, size, nesting); | 674 | phys_addr, size, slot); |
572 | dump_stack(); | 675 | dump_stack(); |
573 | } | 676 | } |
574 | 677 | ||
@@ -579,17 +682,13 @@ void __init *early_ioremap(unsigned long phys_addr, unsigned long size) | |||
579 | return NULL; | 682 | return NULL; |
580 | } | 683 | } |
581 | 684 | ||
582 | if (nesting >= FIX_BTMAPS_NESTING) { | 685 | prev_size[slot] = size; |
583 | WARN_ON(1); | ||
584 | return NULL; | ||
585 | } | ||
586 | early_ioremap_nested++; | ||
587 | /* | 686 | /* |
588 | * Mappings have to be page-aligned | 687 | * Mappings have to be page-aligned |
589 | */ | 688 | */ |
590 | offset = phys_addr & ~PAGE_MASK; | 689 | offset = phys_addr & ~PAGE_MASK; |
591 | phys_addr &= PAGE_MASK; | 690 | phys_addr &= PAGE_MASK; |
592 | size = PAGE_ALIGN(last_addr) - phys_addr; | 691 | size = PAGE_ALIGN(last_addr + 1) - phys_addr; |
593 | 692 | ||
594 | /* | 693 | /* |
595 | * Mappings have to fit in the FIX_BTMAP area. | 694 | * Mappings have to fit in the FIX_BTMAP area. |
@@ -603,10 +702,10 @@ void __init *early_ioremap(unsigned long phys_addr, unsigned long size) | |||
603 | /* | 702 | /* |
604 | * Ok, go for it.. | 703 | * Ok, go for it.. |
605 | */ | 704 | */ |
606 | idx0 = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*nesting; | 705 | idx0 = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*slot; |
607 | idx = idx0; | 706 | idx = idx0; |
608 | while (nrpages > 0) { | 707 | while (nrpages > 0) { |
609 | early_set_fixmap(idx, phys_addr); | 708 | early_set_fixmap(idx, phys_addr, prot); |
610 | phys_addr += PAGE_SIZE; | 709 | phys_addr += PAGE_SIZE; |
611 | --idx; | 710 | --idx; |
612 | --nrpages; | 711 | --nrpages; |
@@ -614,7 +713,20 @@ void __init *early_ioremap(unsigned long phys_addr, unsigned long size) | |||
614 | if (early_ioremap_debug) | 713 | if (early_ioremap_debug) |
615 | printk(KERN_CONT "%08lx + %08lx\n", offset, fix_to_virt(idx0)); | 714 | printk(KERN_CONT "%08lx + %08lx\n", offset, fix_to_virt(idx0)); |
616 | 715 | ||
617 | return (void *) (offset + fix_to_virt(idx0)); | 716 | prev_map[slot] = (void *) (offset + fix_to_virt(idx0)); |
717 | return prev_map[slot]; | ||
718 | } | ||
719 | |||
720 | /* Remap an IO device */ | ||
721 | void __init *early_ioremap(unsigned long phys_addr, unsigned long size) | ||
722 | { | ||
723 | return __early_ioremap(phys_addr, size, PAGE_KERNEL_IO); | ||
724 | } | ||
725 | |||
726 | /* Remap memory */ | ||
727 | void __init *early_memremap(unsigned long phys_addr, unsigned long size) | ||
728 | { | ||
729 | return __early_ioremap(phys_addr, size, PAGE_KERNEL); | ||
618 | } | 730 | } |
619 | 731 | ||
620 | void __init early_iounmap(void *addr, unsigned long size) | 732 | void __init early_iounmap(void *addr, unsigned long size) |
@@ -623,15 +735,33 @@ void __init early_iounmap(void *addr, unsigned long size) | |||
623 | unsigned long offset; | 735 | unsigned long offset; |
624 | unsigned int nrpages; | 736 | unsigned int nrpages; |
625 | enum fixed_addresses idx; | 737 | enum fixed_addresses idx; |
626 | int nesting; | 738 | int i, slot; |
739 | |||
740 | slot = -1; | ||
741 | for (i = 0; i < FIX_BTMAPS_SLOTS; i++) { | ||
742 | if (prev_map[i] == addr) { | ||
743 | slot = i; | ||
744 | break; | ||
745 | } | ||
746 | } | ||
627 | 747 | ||
628 | nesting = --early_ioremap_nested; | 748 | if (slot < 0) { |
629 | if (WARN_ON(nesting < 0)) | 749 | printk(KERN_INFO "early_iounmap(%p, %08lx) not found slot\n", |
750 | addr, size); | ||
751 | WARN_ON(1); | ||
630 | return; | 752 | return; |
753 | } | ||
754 | |||
755 | if (prev_size[slot] != size) { | ||
756 | printk(KERN_INFO "early_iounmap(%p, %08lx) [%d] size not consistent %08lx\n", | ||
757 | addr, size, slot, prev_size[slot]); | ||
758 | WARN_ON(1); | ||
759 | return; | ||
760 | } | ||
631 | 761 | ||
632 | if (early_ioremap_debug) { | 762 | if (early_ioremap_debug) { |
633 | printk(KERN_INFO "early_iounmap(%p, %08lx) [%d]\n", addr, | 763 | printk(KERN_INFO "early_iounmap(%p, %08lx) [%d]\n", addr, |
634 | size, nesting); | 764 | size, slot); |
635 | dump_stack(); | 765 | dump_stack(); |
636 | } | 766 | } |
637 | 767 | ||
@@ -643,12 +773,13 @@ void __init early_iounmap(void *addr, unsigned long size) | |||
643 | offset = virt_addr & ~PAGE_MASK; | 773 | offset = virt_addr & ~PAGE_MASK; |
644 | nrpages = PAGE_ALIGN(offset + size - 1) >> PAGE_SHIFT; | 774 | nrpages = PAGE_ALIGN(offset + size - 1) >> PAGE_SHIFT; |
645 | 775 | ||
646 | idx = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*nesting; | 776 | idx = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*slot; |
647 | while (nrpages > 0) { | 777 | while (nrpages > 0) { |
648 | early_clear_fixmap(idx); | 778 | early_clear_fixmap(idx); |
649 | --idx; | 779 | --idx; |
650 | --nrpages; | 780 | --nrpages; |
651 | } | 781 | } |
782 | prev_map[slot] = 0; | ||
652 | } | 783 | } |
653 | 784 | ||
654 | void __this_fixmap_does_not_exist(void) | 785 | void __this_fixmap_does_not_exist(void) |