aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware/efi/runtime-wrappers.c
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2014-09-30 16:58:52 -0400
committerMatt Fleming <matt.fleming@intel.com>2014-10-03 13:41:03 -0400
commit6d80dba1c9fe4316ef626980102b92fa30c7845a (patch)
tree7d2d4551430d392af7dab18ff755fab1e422fb7b /drivers/firmware/efi/runtime-wrappers.c
parent77e21e87acec8c857df4bfbc647ea21d0a87364d (diff)
efi: Provide a non-blocking SetVariable() operation
There are some circumstances that call for trying to write an EFI variable in a non-blocking way. One such scenario is when writing pstore data in efi_pstore_write() via the pstore_dump() kdump callback. Now that we have an EFI runtime spinlock we need a way of aborting if there is contention instead of spinning, since when writing pstore data from the kdump callback, the runtime lock may already be held by the CPU that's running the callback if we crashed in the middle of an EFI variable operation. The situation is sufficiently special that a new EFI variable operation is warranted. Introduce ->set_variable_nonblocking() for this use case. It is an optional EFI backend operation, and need only be implemented by those backends that usually acquire locks to serialize access to EFI variables, as is the case for virt_efi_set_variable() where we now grab the EFI runtime spinlock. Cc: Peter Zijlstra <peterz@infradead.org> Cc: Ingo Molnar <mingo@kernel.org> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org> Cc: Matthew Garrett <mjg59@srcf.ucam.org> Signed-off-by: Matt Fleming <matt.fleming@intel.com>
Diffstat (limited to 'drivers/firmware/efi/runtime-wrappers.c')
-rw-r--r--drivers/firmware/efi/runtime-wrappers.c19
1 files changed, 19 insertions, 0 deletions
diff --git a/drivers/firmware/efi/runtime-wrappers.c b/drivers/firmware/efi/runtime-wrappers.c
index 9694cba665c4..4349206198b2 100644
--- a/drivers/firmware/efi/runtime-wrappers.c
+++ b/drivers/firmware/efi/runtime-wrappers.c
@@ -200,6 +200,24 @@ static efi_status_t virt_efi_set_variable(efi_char16_t *name,
200 return status; 200 return status;
201} 201}
202 202
203static efi_status_t
204virt_efi_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor,
205 u32 attr, unsigned long data_size,
206 void *data)
207{
208 unsigned long flags;
209 efi_status_t status;
210
211 if (!spin_trylock_irqsave(&efi_runtime_lock, flags))
212 return EFI_NOT_READY;
213
214 status = efi_call_virt(set_variable, name, vendor, attr, data_size,
215 data);
216 spin_unlock_irqrestore(&efi_runtime_lock, flags);
217 return status;
218}
219
220
203static efi_status_t virt_efi_query_variable_info(u32 attr, 221static efi_status_t virt_efi_query_variable_info(u32 attr,
204 u64 *storage_space, 222 u64 *storage_space,
205 u64 *remaining_space, 223 u64 *remaining_space,
@@ -287,6 +305,7 @@ void efi_native_runtime_setup(void)
287 efi.get_variable = virt_efi_get_variable; 305 efi.get_variable = virt_efi_get_variable;
288 efi.get_next_variable = virt_efi_get_next_variable; 306 efi.get_next_variable = virt_efi_get_next_variable;
289 efi.set_variable = virt_efi_set_variable; 307 efi.set_variable = virt_efi_set_variable;
308 efi.set_variable_nonblocking = virt_efi_set_variable_nonblocking;
290 efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count; 309 efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
291 efi.reset_system = virt_efi_reset_system; 310 efi.reset_system = virt_efi_reset_system;
292 efi.query_variable_info = virt_efi_query_variable_info; 311 efi.query_variable_info = virt_efi_query_variable_info;