2 * Re-map IO memory to kernel address space so that we can access it.
3 * This is needed for high PCI addresses that aren't mapped in the
4 * 640k-1MB IO memory area on PC's
6 * (C) Copyright 1995 1996 Linus Torvalds
8 #include <linux/vmalloc.h>
10 #include <linux/sched.h>
12 #include <linux/export.h>
13 #include <asm/cacheflush.h>
14 #include <asm/pgtable.h>
16 #ifdef CONFIG_HAVE_ARCH_HUGE_VMAP
17 static int __read_mostly ioremap_pud_capable
;
18 static int __read_mostly ioremap_pmd_capable
;
19 static int __read_mostly ioremap_huge_disabled
;
21 static int __init
set_nohugeiomap(char *str
)
23 ioremap_huge_disabled
= 1;
26 early_param("nohugeiomap", set_nohugeiomap
);
28 void __init
ioremap_huge_init(void)
30 if (!ioremap_huge_disabled
) {
31 if (arch_ioremap_pud_supported())
32 ioremap_pud_capable
= 1;
33 if (arch_ioremap_pmd_supported())
34 ioremap_pmd_capable
= 1;
38 static inline int ioremap_pud_enabled(void)
40 return ioremap_pud_capable
;
43 static inline int ioremap_pmd_enabled(void)
45 return ioremap_pmd_capable
;
48 #else /* !CONFIG_HAVE_ARCH_HUGE_VMAP */
49 static inline int ioremap_pud_enabled(void) { return 0; }
50 static inline int ioremap_pmd_enabled(void) { return 0; }
51 #endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */
53 static int ioremap_pte_range(pmd_t
*pmd
, unsigned long addr
,
54 unsigned long end
, phys_addr_t phys_addr
, pgprot_t prot
)
59 pfn
= phys_addr
>> PAGE_SHIFT
;
60 pte
= pte_alloc_kernel(pmd
, addr
);
64 BUG_ON(!pte_none(*pte
));
65 set_pte_at(&init_mm
, addr
, pte
, pfn_pte(pfn
, prot
));
67 } while (pte
++, addr
+= PAGE_SIZE
, addr
!= end
);
71 static inline int ioremap_pmd_range(pud_t
*pud
, unsigned long addr
,
72 unsigned long end
, phys_addr_t phys_addr
, pgprot_t prot
)
78 pmd
= pmd_alloc(&init_mm
, pud
, addr
);
82 next
= pmd_addr_end(addr
, end
);
84 if (ioremap_pmd_enabled() &&
85 ((next
- addr
) == PMD_SIZE
) &&
86 IS_ALIGNED(phys_addr
+ addr
, PMD_SIZE
) &&
87 pmd_free_pte_page(pmd
, addr
)) {
88 if (pmd_set_huge(pmd
, phys_addr
+ addr
, prot
))
92 if (ioremap_pte_range(pmd
, addr
, next
, phys_addr
+ addr
, prot
))
94 } while (pmd
++, addr
= next
, addr
!= end
);
98 static inline int ioremap_pud_range(pgd_t
*pgd
, unsigned long addr
,
99 unsigned long end
, phys_addr_t phys_addr
, pgprot_t prot
)
105 pud
= pud_alloc(&init_mm
, pgd
, addr
);
109 next
= pud_addr_end(addr
, end
);
111 if (ioremap_pud_enabled() &&
112 ((next
- addr
) == PUD_SIZE
) &&
113 IS_ALIGNED(phys_addr
+ addr
, PUD_SIZE
) &&
114 pud_free_pmd_page(pud
, addr
)) {
115 if (pud_set_huge(pud
, phys_addr
+ addr
, prot
))
119 if (ioremap_pmd_range(pud
, addr
, next
, phys_addr
+ addr
, prot
))
121 } while (pud
++, addr
= next
, addr
!= end
);
125 int ioremap_page_range(unsigned long addr
,
126 unsigned long end
, phys_addr_t phys_addr
, pgprot_t prot
)
137 pgd
= pgd_offset_k(addr
);
139 next
= pgd_addr_end(addr
, end
);
140 err
= ioremap_pud_range(pgd
, addr
, next
, phys_addr
+addr
, prot
);
143 } while (pgd
++, addr
= next
, addr
!= end
);
145 flush_cache_vmap(start
, end
);
149 EXPORT_SYMBOL_GPL(ioremap_page_range
);