diff options
author | Ingo Molnar <mingo@kernel.org> | 2014-01-05 06:34:29 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2014-01-05 06:34:29 -0500 |
commit | ef0b8b9a521c65201bfca9747ee1bf374296133c (patch) | |
tree | 644c3390c07d06fb7807182a4935f7c3f675b157 /drivers/firmware | |
parent | 5c12af0c41e3417e1939095325920463b5f8e726 (diff) | |
parent | d6e0a2dd12f4067a5bcefb8bbd8ddbeff800afbc (diff) |
Merge tag 'v3.13-rc7' into x86/efi-kexec to resolve conflicts
Conflicts:
arch/x86/platform/efi/efi.c
drivers/firmware/efi/Kconfig
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'drivers/firmware')
-rw-r--r-- | drivers/firmware/Makefile | 1 | ||||
-rw-r--r-- | drivers/firmware/efi/Kconfig | 6 | ||||
-rw-r--r-- | drivers/firmware/efi/Makefile | 2 | ||||
-rw-r--r-- | drivers/firmware/efi/efi-pstore.c | 164 | ||||
-rw-r--r-- | drivers/firmware/efi/efivars.c | 12 | ||||
-rw-r--r-- | drivers/firmware/efi/vars.c | 12 |
6 files changed, 171 insertions, 26 deletions
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 299fad6b5867..5373dc5b6011 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile | |||
@@ -14,3 +14,4 @@ obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o | |||
14 | 14 | ||
15 | obj-$(CONFIG_GOOGLE_FIRMWARE) += google/ | 15 | obj-$(CONFIG_GOOGLE_FIRMWARE) += google/ |
16 | obj-$(CONFIG_EFI) += efi/ | 16 | obj-$(CONFIG_EFI) += efi/ |
17 | obj-$(CONFIG_UEFI_CPER) += efi/ | ||
diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig index 730f5f2e8b7f..1e75f48b61f8 100644 --- a/drivers/firmware/efi/Kconfig +++ b/drivers/firmware/efi/Kconfig | |||
@@ -36,9 +36,6 @@ config EFI_VARS_PSTORE_DEFAULT_DISABLE | |||
36 | backend for pstore by default. This setting can be overridden | 36 | backend for pstore by default. This setting can be overridden |
37 | using the efivars module's pstore_disable parameter. | 37 | using the efivars module's pstore_disable parameter. |
38 | 38 | ||
39 | config UEFI_CPER | ||
40 | def_bool n | ||
41 | |||
42 | config EFI_RUNTIME_MAP | 39 | config EFI_RUNTIME_MAP |
43 | bool "Export efi runtime maps to sysfs" | 40 | bool "Export efi runtime maps to sysfs" |
44 | depends on X86 && EFI && KEXEC | 41 | depends on X86 && EFI && KEXEC |
@@ -51,3 +48,6 @@ config EFI_RUNTIME_MAP | |||
51 | See also Documentation/ABI/testing/sysfs-firmware-efi-runtime-map. | 48 | See also Documentation/ABI/testing/sysfs-firmware-efi-runtime-map. |
52 | 49 | ||
53 | endmenu | 50 | endmenu |
51 | |||
52 | config UEFI_CPER | ||
53 | bool | ||
diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile index a58e0f183a08..9553496b0f43 100644 --- a/drivers/firmware/efi/Makefile +++ b/drivers/firmware/efi/Makefile | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # Makefile for linux kernel | 2 | # Makefile for linux kernel |
3 | # | 3 | # |
4 | obj-y += efi.o vars.o | 4 | obj-$(CONFIG_EFI) += efi.o vars.o |
5 | obj-$(CONFIG_EFI_VARS) += efivars.o | 5 | obj-$(CONFIG_EFI_VARS) += efivars.o |
6 | obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o | 6 | obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o |
7 | obj-$(CONFIG_UEFI_CPER) += cper.o | 7 | obj-$(CONFIG_UEFI_CPER) += cper.o |
diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c index 5002d50e3781..4b9dc836dcf9 100644 --- a/drivers/firmware/efi/efi-pstore.c +++ b/drivers/firmware/efi/efi-pstore.c | |||
@@ -18,14 +18,12 @@ module_param_named(pstore_disable, efivars_pstore_disable, bool, 0644); | |||
18 | 18 | ||
19 | static int efi_pstore_open(struct pstore_info *psi) | 19 | static int efi_pstore_open(struct pstore_info *psi) |
20 | { | 20 | { |
21 | efivar_entry_iter_begin(); | ||
22 | psi->data = NULL; | 21 | psi->data = NULL; |
23 | return 0; | 22 | return 0; |
24 | } | 23 | } |
25 | 24 | ||
26 | static int efi_pstore_close(struct pstore_info *psi) | 25 | static int efi_pstore_close(struct pstore_info *psi) |
27 | { | 26 | { |
28 | efivar_entry_iter_end(); | ||
29 | psi->data = NULL; | 27 | psi->data = NULL; |
30 | return 0; | 28 | return 0; |
31 | } | 29 | } |
@@ -39,6 +37,12 @@ struct pstore_read_data { | |||
39 | char **buf; | 37 | char **buf; |
40 | }; | 38 | }; |
41 | 39 | ||
40 | static inline u64 generic_id(unsigned long timestamp, | ||
41 | unsigned int part, int count) | ||
42 | { | ||
43 | return (timestamp * 100 + part) * 1000 + count; | ||
44 | } | ||
45 | |||
42 | static int efi_pstore_read_func(struct efivar_entry *entry, void *data) | 46 | static int efi_pstore_read_func(struct efivar_entry *entry, void *data) |
43 | { | 47 | { |
44 | efi_guid_t vendor = LINUX_EFI_CRASH_GUID; | 48 | efi_guid_t vendor = LINUX_EFI_CRASH_GUID; |
@@ -57,7 +61,7 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data) | |||
57 | 61 | ||
58 | if (sscanf(name, "dump-type%u-%u-%d-%lu-%c", | 62 | if (sscanf(name, "dump-type%u-%u-%d-%lu-%c", |
59 | cb_data->type, &part, &cnt, &time, &data_type) == 5) { | 63 | cb_data->type, &part, &cnt, &time, &data_type) == 5) { |
60 | *cb_data->id = part; | 64 | *cb_data->id = generic_id(time, part, cnt); |
61 | *cb_data->count = cnt; | 65 | *cb_data->count = cnt; |
62 | cb_data->timespec->tv_sec = time; | 66 | cb_data->timespec->tv_sec = time; |
63 | cb_data->timespec->tv_nsec = 0; | 67 | cb_data->timespec->tv_nsec = 0; |
@@ -67,7 +71,7 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data) | |||
67 | *cb_data->compressed = false; | 71 | *cb_data->compressed = false; |
68 | } else if (sscanf(name, "dump-type%u-%u-%d-%lu", | 72 | } else if (sscanf(name, "dump-type%u-%u-%d-%lu", |
69 | cb_data->type, &part, &cnt, &time) == 4) { | 73 | cb_data->type, &part, &cnt, &time) == 4) { |
70 | *cb_data->id = part; | 74 | *cb_data->id = generic_id(time, part, cnt); |
71 | *cb_data->count = cnt; | 75 | *cb_data->count = cnt; |
72 | cb_data->timespec->tv_sec = time; | 76 | cb_data->timespec->tv_sec = time; |
73 | cb_data->timespec->tv_nsec = 0; | 77 | cb_data->timespec->tv_nsec = 0; |
@@ -79,7 +83,7 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data) | |||
79 | * which doesn't support holding | 83 | * which doesn't support holding |
80 | * multiple logs, remains. | 84 | * multiple logs, remains. |
81 | */ | 85 | */ |
82 | *cb_data->id = part; | 86 | *cb_data->id = generic_id(time, part, 0); |
83 | *cb_data->count = 0; | 87 | *cb_data->count = 0; |
84 | cb_data->timespec->tv_sec = time; | 88 | cb_data->timespec->tv_sec = time; |
85 | cb_data->timespec->tv_nsec = 0; | 89 | cb_data->timespec->tv_nsec = 0; |
@@ -91,19 +95,125 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data) | |||
91 | __efivar_entry_get(entry, &entry->var.Attributes, | 95 | __efivar_entry_get(entry, &entry->var.Attributes, |
92 | &entry->var.DataSize, entry->var.Data); | 96 | &entry->var.DataSize, entry->var.Data); |
93 | size = entry->var.DataSize; | 97 | size = entry->var.DataSize; |
98 | memcpy(*cb_data->buf, entry->var.Data, | ||
99 | (size_t)min_t(unsigned long, EFIVARS_DATA_SIZE_MAX, size)); | ||
94 | 100 | ||
95 | *cb_data->buf = kmemdup(entry->var.Data, size, GFP_KERNEL); | ||
96 | if (*cb_data->buf == NULL) | ||
97 | return -ENOMEM; | ||
98 | return size; | 101 | return size; |
99 | } | 102 | } |
100 | 103 | ||
104 | /** | ||
105 | * efi_pstore_scan_sysfs_enter | ||
106 | * @entry: scanning entry | ||
107 | * @next: next entry | ||
108 | * @head: list head | ||
109 | */ | ||
110 | static void efi_pstore_scan_sysfs_enter(struct efivar_entry *pos, | ||
111 | struct efivar_entry *next, | ||
112 | struct list_head *head) | ||
113 | { | ||
114 | pos->scanning = true; | ||
115 | if (&next->list != head) | ||
116 | next->scanning = true; | ||
117 | } | ||
118 | |||
119 | /** | ||
120 | * __efi_pstore_scan_sysfs_exit | ||
121 | * @entry: deleting entry | ||
122 | * @turn_off_scanning: Check if a scanning flag should be turned off | ||
123 | */ | ||
124 | static inline void __efi_pstore_scan_sysfs_exit(struct efivar_entry *entry, | ||
125 | bool turn_off_scanning) | ||
126 | { | ||
127 | if (entry->deleting) { | ||
128 | list_del(&entry->list); | ||
129 | efivar_entry_iter_end(); | ||
130 | efivar_unregister(entry); | ||
131 | efivar_entry_iter_begin(); | ||
132 | } else if (turn_off_scanning) | ||
133 | entry->scanning = false; | ||
134 | } | ||
135 | |||
136 | /** | ||
137 | * efi_pstore_scan_sysfs_exit | ||
138 | * @pos: scanning entry | ||
139 | * @next: next entry | ||
140 | * @head: list head | ||
141 | * @stop: a flag checking if scanning will stop | ||
142 | */ | ||
143 | static void efi_pstore_scan_sysfs_exit(struct efivar_entry *pos, | ||
144 | struct efivar_entry *next, | ||
145 | struct list_head *head, bool stop) | ||
146 | { | ||
147 | __efi_pstore_scan_sysfs_exit(pos, true); | ||
148 | if (stop) | ||
149 | __efi_pstore_scan_sysfs_exit(next, &next->list != head); | ||
150 | } | ||
151 | |||
152 | /** | ||
153 | * efi_pstore_sysfs_entry_iter | ||
154 | * | ||
155 | * @data: function-specific data to pass to callback | ||
156 | * @pos: entry to begin iterating from | ||
157 | * | ||
158 | * You MUST call efivar_enter_iter_begin() before this function, and | ||
159 | * efivar_entry_iter_end() afterwards. | ||
160 | * | ||
161 | * It is possible to begin iteration from an arbitrary entry within | ||
162 | * the list by passing @pos. @pos is updated on return to point to | ||
163 | * the next entry of the last one passed to efi_pstore_read_func(). | ||
164 | * To begin iterating from the beginning of the list @pos must be %NULL. | ||
165 | */ | ||
166 | static int efi_pstore_sysfs_entry_iter(void *data, struct efivar_entry **pos) | ||
167 | { | ||
168 | struct efivar_entry *entry, *n; | ||
169 | struct list_head *head = &efivar_sysfs_list; | ||
170 | int size = 0; | ||
171 | |||
172 | if (!*pos) { | ||
173 | list_for_each_entry_safe(entry, n, head, list) { | ||
174 | efi_pstore_scan_sysfs_enter(entry, n, head); | ||
175 | |||
176 | size = efi_pstore_read_func(entry, data); | ||
177 | efi_pstore_scan_sysfs_exit(entry, n, head, size < 0); | ||
178 | if (size) | ||
179 | break; | ||
180 | } | ||
181 | *pos = n; | ||
182 | return size; | ||
183 | } | ||
184 | |||
185 | list_for_each_entry_safe_from((*pos), n, head, list) { | ||
186 | efi_pstore_scan_sysfs_enter((*pos), n, head); | ||
187 | |||
188 | size = efi_pstore_read_func((*pos), data); | ||
189 | efi_pstore_scan_sysfs_exit((*pos), n, head, size < 0); | ||
190 | if (size) | ||
191 | break; | ||
192 | } | ||
193 | *pos = n; | ||
194 | return size; | ||
195 | } | ||
196 | |||
197 | /** | ||
198 | * efi_pstore_read | ||
199 | * | ||
200 | * This function returns a size of NVRAM entry logged via efi_pstore_write(). | ||
201 | * The meaning and behavior of efi_pstore/pstore are as below. | ||
202 | * | ||
203 | * size > 0: Got data of an entry logged via efi_pstore_write() successfully, | ||
204 | * and pstore filesystem will continue reading subsequent entries. | ||
205 | * size == 0: Entry was not logged via efi_pstore_write(), | ||
206 | * and efi_pstore driver will continue reading subsequent entries. | ||
207 | * size < 0: Failed to get data of entry logging via efi_pstore_write(), | ||
208 | * and pstore will stop reading entry. | ||
209 | */ | ||
101 | static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, | 210 | static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, |
102 | int *count, struct timespec *timespec, | 211 | int *count, struct timespec *timespec, |
103 | char **buf, bool *compressed, | 212 | char **buf, bool *compressed, |
104 | struct pstore_info *psi) | 213 | struct pstore_info *psi) |
105 | { | 214 | { |
106 | struct pstore_read_data data; | 215 | struct pstore_read_data data; |
216 | ssize_t size; | ||
107 | 217 | ||
108 | data.id = id; | 218 | data.id = id; |
109 | data.type = type; | 219 | data.type = type; |
@@ -112,8 +222,17 @@ static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, | |||
112 | data.compressed = compressed; | 222 | data.compressed = compressed; |
113 | data.buf = buf; | 223 | data.buf = buf; |
114 | 224 | ||
115 | return __efivar_entry_iter(efi_pstore_read_func, &efivar_sysfs_list, &data, | 225 | *data.buf = kzalloc(EFIVARS_DATA_SIZE_MAX, GFP_KERNEL); |
116 | (struct efivar_entry **)&psi->data); | 226 | if (!*data.buf) |
227 | return -ENOMEM; | ||
228 | |||
229 | efivar_entry_iter_begin(); | ||
230 | size = efi_pstore_sysfs_entry_iter(&data, | ||
231 | (struct efivar_entry **)&psi->data); | ||
232 | efivar_entry_iter_end(); | ||
233 | if (size <= 0) | ||
234 | kfree(*data.buf); | ||
235 | return size; | ||
117 | } | 236 | } |
118 | 237 | ||
119 | static int efi_pstore_write(enum pstore_type_id type, | 238 | static int efi_pstore_write(enum pstore_type_id type, |
@@ -184,9 +303,17 @@ static int efi_pstore_erase_func(struct efivar_entry *entry, void *data) | |||
184 | return 0; | 303 | return 0; |
185 | } | 304 | } |
186 | 305 | ||
306 | if (entry->scanning) { | ||
307 | /* | ||
308 | * Skip deletion because this entry will be deleted | ||
309 | * after scanning is completed. | ||
310 | */ | ||
311 | entry->deleting = true; | ||
312 | } else | ||
313 | list_del(&entry->list); | ||
314 | |||
187 | /* found */ | 315 | /* found */ |
188 | __efivar_entry_delete(entry); | 316 | __efivar_entry_delete(entry); |
189 | list_del(&entry->list); | ||
190 | 317 | ||
191 | return 1; | 318 | return 1; |
192 | } | 319 | } |
@@ -199,14 +326,16 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count, | |||
199 | char name[DUMP_NAME_LEN]; | 326 | char name[DUMP_NAME_LEN]; |
200 | efi_char16_t efi_name[DUMP_NAME_LEN]; | 327 | efi_char16_t efi_name[DUMP_NAME_LEN]; |
201 | int found, i; | 328 | int found, i; |
329 | unsigned int part; | ||
202 | 330 | ||
203 | sprintf(name, "dump-type%u-%u-%d-%lu", type, (unsigned int)id, count, | 331 | do_div(id, 1000); |
204 | time.tv_sec); | 332 | part = do_div(id, 100); |
333 | sprintf(name, "dump-type%u-%u-%d-%lu", type, part, count, time.tv_sec); | ||
205 | 334 | ||
206 | for (i = 0; i < DUMP_NAME_LEN; i++) | 335 | for (i = 0; i < DUMP_NAME_LEN; i++) |
207 | efi_name[i] = name[i]; | 336 | efi_name[i] = name[i]; |
208 | 337 | ||
209 | edata.id = id; | 338 | edata.id = part; |
210 | edata.type = type; | 339 | edata.type = type; |
211 | edata.count = count; | 340 | edata.count = count; |
212 | edata.time = time; | 341 | edata.time = time; |
@@ -214,10 +343,12 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count, | |||
214 | 343 | ||
215 | efivar_entry_iter_begin(); | 344 | efivar_entry_iter_begin(); |
216 | found = __efivar_entry_iter(efi_pstore_erase_func, &efivar_sysfs_list, &edata, &entry); | 345 | found = __efivar_entry_iter(efi_pstore_erase_func, &efivar_sysfs_list, &edata, &entry); |
217 | efivar_entry_iter_end(); | ||
218 | 346 | ||
219 | if (found) | 347 | if (found && !entry->scanning) { |
348 | efivar_entry_iter_end(); | ||
220 | efivar_unregister(entry); | 349 | efivar_unregister(entry); |
350 | } else | ||
351 | efivar_entry_iter_end(); | ||
221 | 352 | ||
222 | return 0; | 353 | return 0; |
223 | } | 354 | } |
@@ -225,6 +356,7 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count, | |||
225 | static struct pstore_info efi_pstore_info = { | 356 | static struct pstore_info efi_pstore_info = { |
226 | .owner = THIS_MODULE, | 357 | .owner = THIS_MODULE, |
227 | .name = "efi", | 358 | .name = "efi", |
359 | .flags = PSTORE_FLAGS_FRAGILE, | ||
228 | .open = efi_pstore_open, | 360 | .open = efi_pstore_open, |
229 | .close = efi_pstore_close, | 361 | .close = efi_pstore_close, |
230 | .read = efi_pstore_read, | 362 | .read = efi_pstore_read, |
diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c index 933eb027d527..3dc248239197 100644 --- a/drivers/firmware/efi/efivars.c +++ b/drivers/firmware/efi/efivars.c | |||
@@ -383,12 +383,16 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj, | |||
383 | else if (__efivar_entry_delete(entry)) | 383 | else if (__efivar_entry_delete(entry)) |
384 | err = -EIO; | 384 | err = -EIO; |
385 | 385 | ||
386 | efivar_entry_iter_end(); | 386 | if (err) { |
387 | 387 | efivar_entry_iter_end(); | |
388 | if (err) | ||
389 | return err; | 388 | return err; |
389 | } | ||
390 | 390 | ||
391 | efivar_unregister(entry); | 391 | if (!entry->scanning) { |
392 | efivar_entry_iter_end(); | ||
393 | efivar_unregister(entry); | ||
394 | } else | ||
395 | efivar_entry_iter_end(); | ||
392 | 396 | ||
393 | /* It's dead Jim.... */ | 397 | /* It's dead Jim.... */ |
394 | return count; | 398 | return count; |
diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c index 391c67b182d9..b22659cccca4 100644 --- a/drivers/firmware/efi/vars.c +++ b/drivers/firmware/efi/vars.c | |||
@@ -683,8 +683,16 @@ struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid, | |||
683 | if (!found) | 683 | if (!found) |
684 | return NULL; | 684 | return NULL; |
685 | 685 | ||
686 | if (remove) | 686 | if (remove) { |
687 | list_del(&entry->list); | 687 | if (entry->scanning) { |
688 | /* | ||
689 | * The entry will be deleted | ||
690 | * after scanning is completed. | ||
691 | */ | ||
692 | entry->deleting = true; | ||
693 | } else | ||
694 | list_del(&entry->list); | ||
695 | } | ||
688 | 696 | ||
689 | return entry; | 697 | return entry; |
690 | } | 698 | } |