diff options
author | Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> | 2010-06-17 23:22:40 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2010-07-09 14:42:03 -0400 |
commit | ffa71f33a820d1ab3f2fc5723819ac60fb76080b (patch) | |
tree | fb7fb08c43a773f771a49ac765e9330e07d32eef /lib | |
parent | d7a0380dc3e6607d30ccdfc3cfc2ccee0d966716 (diff) |
x86, ioremap: Fix incorrect physical address handling in PAE mode
Current x86 ioremap() doesn't handle physical address higher than
32-bit properly in X86_32 PAE mode. When physical address higher than
32-bit is passed to ioremap(), higher 32-bits in physical address is
cleared wrongly. Due to this bug, ioremap() can map wrong address to
linear address space.
In my case, 64-bit MMIO region was assigned to a PCI device (ioat
device) on my system. Because of the ioremap()'s bug, wrong physical
address (instead of MMIO region) was mapped to linear address space.
Because of this, loading ioatdma driver caused unexpected behavior
(kernel panic, kernel hangup, ...).
Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
LKML-Reference: <4C1AE680.7090408@jp.fujitsu.com>
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/ioremap.c | 10 |
1 files changed, 5 insertions, 5 deletions
diff --git a/lib/ioremap.c b/lib/ioremap.c index 14c6078f17a2..5730ecd3eb66 100644 --- a/lib/ioremap.c +++ b/lib/ioremap.c | |||
@@ -13,10 +13,10 @@ | |||
13 | #include <asm/pgtable.h> | 13 | #include <asm/pgtable.h> |
14 | 14 | ||
15 | static int ioremap_pte_range(pmd_t *pmd, unsigned long addr, | 15 | static int ioremap_pte_range(pmd_t *pmd, unsigned long addr, |
16 | unsigned long end, unsigned long phys_addr, pgprot_t prot) | 16 | unsigned long end, phys_addr_t phys_addr, pgprot_t prot) |
17 | { | 17 | { |
18 | pte_t *pte; | 18 | pte_t *pte; |
19 | unsigned long pfn; | 19 | u64 pfn; |
20 | 20 | ||
21 | pfn = phys_addr >> PAGE_SHIFT; | 21 | pfn = phys_addr >> PAGE_SHIFT; |
22 | pte = pte_alloc_kernel(pmd, addr); | 22 | pte = pte_alloc_kernel(pmd, addr); |
@@ -31,7 +31,7 @@ static int ioremap_pte_range(pmd_t *pmd, unsigned long addr, | |||
31 | } | 31 | } |
32 | 32 | ||
33 | static inline int ioremap_pmd_range(pud_t *pud, unsigned long addr, | 33 | static inline int ioremap_pmd_range(pud_t *pud, unsigned long addr, |
34 | unsigned long end, unsigned long phys_addr, pgprot_t prot) | 34 | unsigned long end, phys_addr_t phys_addr, pgprot_t prot) |
35 | { | 35 | { |
36 | pmd_t *pmd; | 36 | pmd_t *pmd; |
37 | unsigned long next; | 37 | unsigned long next; |
@@ -49,7 +49,7 @@ static inline int ioremap_pmd_range(pud_t *pud, unsigned long addr, | |||
49 | } | 49 | } |
50 | 50 | ||
51 | static inline int ioremap_pud_range(pgd_t *pgd, unsigned long addr, | 51 | static inline int ioremap_pud_range(pgd_t *pgd, unsigned long addr, |
52 | unsigned long end, unsigned long phys_addr, pgprot_t prot) | 52 | unsigned long end, phys_addr_t phys_addr, pgprot_t prot) |
53 | { | 53 | { |
54 | pud_t *pud; | 54 | pud_t *pud; |
55 | unsigned long next; | 55 | unsigned long next; |
@@ -67,7 +67,7 @@ static inline int ioremap_pud_range(pgd_t *pgd, unsigned long addr, | |||
67 | } | 67 | } |
68 | 68 | ||
69 | int ioremap_page_range(unsigned long addr, | 69 | int ioremap_page_range(unsigned long addr, |
70 | unsigned long end, unsigned long phys_addr, pgprot_t prot) | 70 | unsigned long end, phys_addr_t phys_addr, pgprot_t prot) |
71 | { | 71 | { |
72 | pgd_t *pgd; | 72 | pgd_t *pgd; |
73 | unsigned long start; | 73 | unsigned long start; |