diff options
author | Yinghai Lu <yinghai@kernel.org> | 2009-06-16 18:31:16 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-16 22:47:28 -0400 |
commit | 3b0fde0fac19c180317eb0601b3504083f4b9bf5 (patch) | |
tree | 5458ec10f3c6759ec64c6fa27e12e692a575d07a | |
parent | 021415468c889979117b1a07b96f7e36de33e995 (diff) |
firmware_map: fix hang with x86/32bit
Addresses http://bugzilla.kernel.org/show_bug.cgi?id=13484
Peer reported:
| The bug is introduced from kernel 2.6.27, if E820 table reserve the memory
| above 4G in 32bit OS(BIOS-e820: 00000000fff80000 - 0000000120000000
| (reserved)), system will report Int 6 error and hang up. The bug is caused by
| the following code in drivers/firmware/memmap.c, the resource_size_t is 32bit
| variable in 32bit OS, the BUG_ON() will be invoked to result in the Int 6
| error. I try the latest 32bit Ubuntu and Fedora distributions, all hit this
| bug.
|======
|static int firmware_map_add_entry(resource_size_t start, resource_size_t end,
| const char *type,
| struct firmware_map_entry *entry)
and it only happen with CONFIG_PHYS_ADDR_T_64BIT is not set.
it turns out we need to pass u64 instead of resource_size_t for that.
[akpm@linux-foundation.org: add comment]
Reported-and-tested-by: Peer Chen <pchen@nvidia.com>
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Cc: Ingo Molnar <mingo@elte.hu>
Acked-by: H. Peter Anvin <hpa@zytor.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: <stable@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/firmware/memmap.c | 16 | ||||
-rw-r--r-- | include/linux/firmware-map.h | 12 |
2 files changed, 13 insertions, 15 deletions
diff --git a/drivers/firmware/memmap.c b/drivers/firmware/memmap.c index 05aa2d406ac6..d5ea8a68d338 100644 --- a/drivers/firmware/memmap.c +++ b/drivers/firmware/memmap.c | |||
@@ -31,8 +31,12 @@ | |||
31 | * information is necessary as for the resource tree. | 31 | * information is necessary as for the resource tree. |
32 | */ | 32 | */ |
33 | struct firmware_map_entry { | 33 | struct firmware_map_entry { |
34 | resource_size_t start; /* start of the memory range */ | 34 | /* |
35 | resource_size_t end; /* end of the memory range (incl.) */ | 35 | * start and end must be u64 rather than resource_size_t, because e820 |
36 | * resources can lie at addresses above 4G. | ||
37 | */ | ||
38 | u64 start; /* start of the memory range */ | ||
39 | u64 end; /* end of the memory range (incl.) */ | ||
36 | const char *type; /* type of the memory range */ | 40 | const char *type; /* type of the memory range */ |
37 | struct list_head list; /* entry for the linked list */ | 41 | struct list_head list; /* entry for the linked list */ |
38 | struct kobject kobj; /* kobject for each entry */ | 42 | struct kobject kobj; /* kobject for each entry */ |
@@ -101,7 +105,7 @@ static LIST_HEAD(map_entries); | |||
101 | * Common implementation of firmware_map_add() and firmware_map_add_early() | 105 | * Common implementation of firmware_map_add() and firmware_map_add_early() |
102 | * which expects a pre-allocated struct firmware_map_entry. | 106 | * which expects a pre-allocated struct firmware_map_entry. |
103 | **/ | 107 | **/ |
104 | static int firmware_map_add_entry(resource_size_t start, resource_size_t end, | 108 | static int firmware_map_add_entry(u64 start, u64 end, |
105 | const char *type, | 109 | const char *type, |
106 | struct firmware_map_entry *entry) | 110 | struct firmware_map_entry *entry) |
107 | { | 111 | { |
@@ -132,8 +136,7 @@ static int firmware_map_add_entry(resource_size_t start, resource_size_t end, | |||
132 | * | 136 | * |
133 | * Returns 0 on success, or -ENOMEM if no memory could be allocated. | 137 | * Returns 0 on success, or -ENOMEM if no memory could be allocated. |
134 | **/ | 138 | **/ |
135 | int firmware_map_add(resource_size_t start, resource_size_t end, | 139 | int firmware_map_add(u64 start, u64 end, const char *type) |
136 | const char *type) | ||
137 | { | 140 | { |
138 | struct firmware_map_entry *entry; | 141 | struct firmware_map_entry *entry; |
139 | 142 | ||
@@ -157,8 +160,7 @@ int firmware_map_add(resource_size_t start, resource_size_t end, | |||
157 | * | 160 | * |
158 | * Returns 0 on success, or -ENOMEM if no memory could be allocated. | 161 | * Returns 0 on success, or -ENOMEM if no memory could be allocated. |
159 | **/ | 162 | **/ |
160 | int __init firmware_map_add_early(resource_size_t start, resource_size_t end, | 163 | int __init firmware_map_add_early(u64 start, u64 end, const char *type) |
161 | const char *type) | ||
162 | { | 164 | { |
163 | struct firmware_map_entry *entry; | 165 | struct firmware_map_entry *entry; |
164 | 166 | ||
diff --git a/include/linux/firmware-map.h b/include/linux/firmware-map.h index cca686b39123..875451f1373a 100644 --- a/include/linux/firmware-map.h +++ b/include/linux/firmware-map.h | |||
@@ -24,21 +24,17 @@ | |||
24 | */ | 24 | */ |
25 | #ifdef CONFIG_FIRMWARE_MEMMAP | 25 | #ifdef CONFIG_FIRMWARE_MEMMAP |
26 | 26 | ||
27 | int firmware_map_add(resource_size_t start, resource_size_t end, | 27 | int firmware_map_add(u64 start, u64 end, const char *type); |
28 | const char *type); | 28 | int firmware_map_add_early(u64 start, u64 end, const char *type); |
29 | int firmware_map_add_early(resource_size_t start, resource_size_t end, | ||
30 | const char *type); | ||
31 | 29 | ||
32 | #else /* CONFIG_FIRMWARE_MEMMAP */ | 30 | #else /* CONFIG_FIRMWARE_MEMMAP */ |
33 | 31 | ||
34 | static inline int firmware_map_add(resource_size_t start, resource_size_t end, | 32 | static inline int firmware_map_add(u64 start, u64 end, const char *type) |
35 | const char *type) | ||
36 | { | 33 | { |
37 | return 0; | 34 | return 0; |
38 | } | 35 | } |
39 | 36 | ||
40 | static inline int firmware_map_add_early(resource_size_t start, | 37 | static inline int firmware_map_add_early(u64 start, u64 end, const char *type) |
41 | resource_size_t end, const char *type) | ||
42 | { | 38 | { |
43 | return 0; | 39 | return 0; |
44 | } | 40 | } |