diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2013-07-04 17:11:22 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2013-07-04 17:11:22 -0400 |
commit | 2b0f89317e99735bbf32eaede81f707f98ab1b5e (patch) | |
tree | 16daa236e21876b11f1c0b9256cd4046aadba020 /arch/x86/platform | |
parent | 07bd1172902e782f288e4d44b1fde7dec0f08b6f (diff) | |
parent | fa18f7bde3ad4568d1d343b60d963bfbd8dc3991 (diff) |
Merge branch 'timers/posix-cpu-timers-for-tglx' of
git://git.kernel.org/pub/scm/linux/kernel/git/frederic/linux-dynticks into timers/core
Frederic sayed: "Most of these patches have been hanging around for
several month now, in -mmotm for a significant chunk. They already
missed a few releases."
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86/platform')
-rw-r--r-- | arch/x86/platform/efi/efi.c | 193 |
1 files changed, 70 insertions, 123 deletions
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index dd3b82530145..90f6ed127096 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c | |||
@@ -42,7 +42,6 @@ | |||
42 | #include <linux/io.h> | 42 | #include <linux/io.h> |
43 | #include <linux/reboot.h> | 43 | #include <linux/reboot.h> |
44 | #include <linux/bcd.h> | 44 | #include <linux/bcd.h> |
45 | #include <linux/ucs2_string.h> | ||
46 | 45 | ||
47 | #include <asm/setup.h> | 46 | #include <asm/setup.h> |
48 | #include <asm/efi.h> | 47 | #include <asm/efi.h> |
@@ -54,12 +53,12 @@ | |||
54 | 53 | ||
55 | #define EFI_DEBUG 1 | 54 | #define EFI_DEBUG 1 |
56 | 55 | ||
57 | /* | 56 | #define EFI_MIN_RESERVE 5120 |
58 | * There's some additional metadata associated with each | 57 | |
59 | * variable. Intel's reference implementation is 60 bytes - bump that | 58 | #define EFI_DUMMY_GUID \ |
60 | * to account for potential alignment constraints | 59 | EFI_GUID(0x4424ac57, 0xbe4b, 0x47dd, 0x9e, 0x97, 0xed, 0x50, 0xf0, 0x9f, 0x92, 0xa9) |
61 | */ | 60 | |
62 | #define VAR_METADATA_SIZE 64 | 61 | static efi_char16_t efi_dummy_name[6] = { 'D', 'U', 'M', 'M', 'Y', 0 }; |
63 | 62 | ||
64 | struct efi __read_mostly efi = { | 63 | struct efi __read_mostly efi = { |
65 | .mps = EFI_INVALID_TABLE_ADDR, | 64 | .mps = EFI_INVALID_TABLE_ADDR, |
@@ -79,13 +78,6 @@ struct efi_memory_map memmap; | |||
79 | static struct efi efi_phys __initdata; | 78 | static struct efi efi_phys __initdata; |
80 | static efi_system_table_t efi_systab __initdata; | 79 | static efi_system_table_t efi_systab __initdata; |
81 | 80 | ||
82 | static u64 efi_var_store_size; | ||
83 | static u64 efi_var_remaining_size; | ||
84 | static u64 efi_var_max_var_size; | ||
85 | static u64 boot_used_size; | ||
86 | static u64 boot_var_size; | ||
87 | static u64 active_size; | ||
88 | |||
89 | unsigned long x86_efi_facility; | 81 | unsigned long x86_efi_facility; |
90 | 82 | ||
91 | /* | 83 | /* |
@@ -188,53 +180,8 @@ static efi_status_t virt_efi_get_next_variable(unsigned long *name_size, | |||
188 | efi_char16_t *name, | 180 | efi_char16_t *name, |
189 | efi_guid_t *vendor) | 181 | efi_guid_t *vendor) |
190 | { | 182 | { |
191 | efi_status_t status; | 183 | return efi_call_virt3(get_next_variable, |
192 | static bool finished = false; | 184 | name_size, name, vendor); |
193 | static u64 var_size; | ||
194 | |||
195 | status = efi_call_virt3(get_next_variable, | ||
196 | name_size, name, vendor); | ||
197 | |||
198 | if (status == EFI_NOT_FOUND) { | ||
199 | finished = true; | ||
200 | if (var_size < boot_used_size) { | ||
201 | boot_var_size = boot_used_size - var_size; | ||
202 | active_size += boot_var_size; | ||
203 | } else { | ||
204 | printk(KERN_WARNING FW_BUG "efi: Inconsistent initial sizes\n"); | ||
205 | } | ||
206 | } | ||
207 | |||
208 | if (boot_used_size && !finished) { | ||
209 | unsigned long size; | ||
210 | u32 attr; | ||
211 | efi_status_t s; | ||
212 | void *tmp; | ||
213 | |||
214 | s = virt_efi_get_variable(name, vendor, &attr, &size, NULL); | ||
215 | |||
216 | if (s != EFI_BUFFER_TOO_SMALL || !size) | ||
217 | return status; | ||
218 | |||
219 | tmp = kmalloc(size, GFP_ATOMIC); | ||
220 | |||
221 | if (!tmp) | ||
222 | return status; | ||
223 | |||
224 | s = virt_efi_get_variable(name, vendor, &attr, &size, tmp); | ||
225 | |||
226 | if (s == EFI_SUCCESS && (attr & EFI_VARIABLE_NON_VOLATILE)) { | ||
227 | var_size += size; | ||
228 | var_size += ucs2_strsize(name, 1024); | ||
229 | active_size += size; | ||
230 | active_size += VAR_METADATA_SIZE; | ||
231 | active_size += ucs2_strsize(name, 1024); | ||
232 | } | ||
233 | |||
234 | kfree(tmp); | ||
235 | } | ||
236 | |||
237 | return status; | ||
238 | } | 185 | } |
239 | 186 | ||
240 | static efi_status_t virt_efi_set_variable(efi_char16_t *name, | 187 | static efi_status_t virt_efi_set_variable(efi_char16_t *name, |
@@ -243,34 +190,9 @@ static efi_status_t virt_efi_set_variable(efi_char16_t *name, | |||
243 | unsigned long data_size, | 190 | unsigned long data_size, |
244 | void *data) | 191 | void *data) |
245 | { | 192 | { |
246 | efi_status_t status; | 193 | return efi_call_virt5(set_variable, |
247 | u32 orig_attr = 0; | 194 | name, vendor, attr, |
248 | unsigned long orig_size = 0; | 195 | data_size, data); |
249 | |||
250 | status = virt_efi_get_variable(name, vendor, &orig_attr, &orig_size, | ||
251 | NULL); | ||
252 | |||
253 | if (status != EFI_BUFFER_TOO_SMALL) | ||
254 | orig_size = 0; | ||
255 | |||
256 | status = efi_call_virt5(set_variable, | ||
257 | name, vendor, attr, | ||
258 | data_size, data); | ||
259 | |||
260 | if (status == EFI_SUCCESS) { | ||
261 | if (orig_size) { | ||
262 | active_size -= orig_size; | ||
263 | active_size -= ucs2_strsize(name, 1024); | ||
264 | active_size -= VAR_METADATA_SIZE; | ||
265 | } | ||
266 | if (data_size) { | ||
267 | active_size += data_size; | ||
268 | active_size += ucs2_strsize(name, 1024); | ||
269 | active_size += VAR_METADATA_SIZE; | ||
270 | } | ||
271 | } | ||
272 | |||
273 | return status; | ||
274 | } | 196 | } |
275 | 197 | ||
276 | static efi_status_t virt_efi_query_variable_info(u32 attr, | 198 | static efi_status_t virt_efi_query_variable_info(u32 attr, |
@@ -788,9 +710,6 @@ void __init efi_init(void) | |||
788 | char vendor[100] = "unknown"; | 710 | char vendor[100] = "unknown"; |
789 | int i = 0; | 711 | int i = 0; |
790 | void *tmp; | 712 | void *tmp; |
791 | struct setup_data *data; | ||
792 | struct efi_var_bootdata *efi_var_data; | ||
793 | u64 pa_data; | ||
794 | 713 | ||
795 | #ifdef CONFIG_X86_32 | 714 | #ifdef CONFIG_X86_32 |
796 | if (boot_params.efi_info.efi_systab_hi || | 715 | if (boot_params.efi_info.efi_systab_hi || |
@@ -808,22 +727,6 @@ void __init efi_init(void) | |||
808 | if (efi_systab_init(efi_phys.systab)) | 727 | if (efi_systab_init(efi_phys.systab)) |
809 | return; | 728 | return; |
810 | 729 | ||
811 | pa_data = boot_params.hdr.setup_data; | ||
812 | while (pa_data) { | ||
813 | data = early_ioremap(pa_data, sizeof(*efi_var_data)); | ||
814 | if (data->type == SETUP_EFI_VARS) { | ||
815 | efi_var_data = (struct efi_var_bootdata *)data; | ||
816 | |||
817 | efi_var_store_size = efi_var_data->store_size; | ||
818 | efi_var_remaining_size = efi_var_data->remaining_size; | ||
819 | efi_var_max_var_size = efi_var_data->max_var_size; | ||
820 | } | ||
821 | pa_data = data->next; | ||
822 | early_iounmap(data, sizeof(*efi_var_data)); | ||
823 | } | ||
824 | |||
825 | boot_used_size = efi_var_store_size - efi_var_remaining_size; | ||
826 | |||
827 | set_bit(EFI_SYSTEM_TABLES, &x86_efi_facility); | 730 | set_bit(EFI_SYSTEM_TABLES, &x86_efi_facility); |
828 | 731 | ||
829 | /* | 732 | /* |
@@ -1087,6 +990,13 @@ void __init efi_enter_virtual_mode(void) | |||
1087 | runtime_code_page_mkexec(); | 990 | runtime_code_page_mkexec(); |
1088 | 991 | ||
1089 | kfree(new_memmap); | 992 | kfree(new_memmap); |
993 | |||
994 | /* clean DUMMY object */ | ||
995 | efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID, | ||
996 | EFI_VARIABLE_NON_VOLATILE | | ||
997 | EFI_VARIABLE_BOOTSERVICE_ACCESS | | ||
998 | EFI_VARIABLE_RUNTIME_ACCESS, | ||
999 | 0, NULL); | ||
1090 | } | 1000 | } |
1091 | 1001 | ||
1092 | /* | 1002 | /* |
@@ -1138,33 +1048,70 @@ efi_status_t efi_query_variable_store(u32 attributes, unsigned long size) | |||
1138 | efi_status_t status; | 1048 | efi_status_t status; |
1139 | u64 storage_size, remaining_size, max_size; | 1049 | u64 storage_size, remaining_size, max_size; |
1140 | 1050 | ||
1051 | if (!(attributes & EFI_VARIABLE_NON_VOLATILE)) | ||
1052 | return 0; | ||
1053 | |||
1141 | status = efi.query_variable_info(attributes, &storage_size, | 1054 | status = efi.query_variable_info(attributes, &storage_size, |
1142 | &remaining_size, &max_size); | 1055 | &remaining_size, &max_size); |
1143 | if (status != EFI_SUCCESS) | 1056 | if (status != EFI_SUCCESS) |
1144 | return status; | 1057 | return status; |
1145 | 1058 | ||
1146 | if (!max_size && remaining_size > size) | ||
1147 | printk_once(KERN_ERR FW_BUG "Broken EFI implementation" | ||
1148 | " is returning MaxVariableSize=0\n"); | ||
1149 | /* | 1059 | /* |
1150 | * Some firmware implementations refuse to boot if there's insufficient | 1060 | * Some firmware implementations refuse to boot if there's insufficient |
1151 | * space in the variable store. We account for that by refusing the | 1061 | * space in the variable store. We account for that by refusing the |
1152 | * write if permitting it would reduce the available space to under | 1062 | * write if permitting it would reduce the available space to under |
1153 | * 50%. However, some firmware won't reclaim variable space until | 1063 | * 5KB. This figure was provided by Samsung, so should be safe. |
1154 | * after the used (not merely the actively used) space drops below | ||
1155 | * a threshold. We can approximate that case with the value calculated | ||
1156 | * above. If both the firmware and our calculations indicate that the | ||
1157 | * available space would drop below 50%, refuse the write. | ||
1158 | */ | 1064 | */ |
1065 | if ((remaining_size - size < EFI_MIN_RESERVE) && | ||
1066 | !efi_no_storage_paranoia) { | ||
1067 | |||
1068 | /* | ||
1069 | * Triggering garbage collection may require that the firmware | ||
1070 | * generate a real EFI_OUT_OF_RESOURCES error. We can force | ||
1071 | * that by attempting to use more space than is available. | ||
1072 | */ | ||
1073 | unsigned long dummy_size = remaining_size + 1024; | ||
1074 | void *dummy = kzalloc(dummy_size, GFP_ATOMIC); | ||
1075 | |||
1076 | if (!dummy) | ||
1077 | return EFI_OUT_OF_RESOURCES; | ||
1078 | |||
1079 | status = efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID, | ||
1080 | EFI_VARIABLE_NON_VOLATILE | | ||
1081 | EFI_VARIABLE_BOOTSERVICE_ACCESS | | ||
1082 | EFI_VARIABLE_RUNTIME_ACCESS, | ||
1083 | dummy_size, dummy); | ||
1084 | |||
1085 | if (status == EFI_SUCCESS) { | ||
1086 | /* | ||
1087 | * This should have failed, so if it didn't make sure | ||
1088 | * that we delete it... | ||
1089 | */ | ||
1090 | efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID, | ||
1091 | EFI_VARIABLE_NON_VOLATILE | | ||
1092 | EFI_VARIABLE_BOOTSERVICE_ACCESS | | ||
1093 | EFI_VARIABLE_RUNTIME_ACCESS, | ||
1094 | 0, dummy); | ||
1095 | } | ||
1096 | |||
1097 | kfree(dummy); | ||
1159 | 1098 | ||
1160 | if (!storage_size || size > remaining_size || | 1099 | /* |
1161 | (max_size && size > max_size)) | 1100 | * The runtime code may now have triggered a garbage collection |
1162 | return EFI_OUT_OF_RESOURCES; | 1101 | * run, so check the variable info again |
1102 | */ | ||
1103 | status = efi.query_variable_info(attributes, &storage_size, | ||
1104 | &remaining_size, &max_size); | ||
1163 | 1105 | ||
1164 | if (!efi_no_storage_paranoia && | 1106 | if (status != EFI_SUCCESS) |
1165 | ((active_size + size + VAR_METADATA_SIZE > storage_size / 2) && | 1107 | return status; |
1166 | (remaining_size - size < storage_size / 2))) | 1108 | |
1167 | return EFI_OUT_OF_RESOURCES; | 1109 | /* |
1110 | * There still isn't enough room, so return an error | ||
1111 | */ | ||
1112 | if (remaining_size - size < EFI_MIN_RESERVE) | ||
1113 | return EFI_OUT_OF_RESOURCES; | ||
1114 | } | ||
1168 | 1115 | ||
1169 | return EFI_SUCCESS; | 1116 | return EFI_SUCCESS; |
1170 | } | 1117 | } |