> > diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c > > index ac5db5f8dbbf..4714b305ca90 100644 > > --- a/drivers/firmware/efi/efi.c > > +++ b/drivers/firmware/efi/efi.c > > @@ -76,6 +76,8 @@ static unsigned long *efi_tables[] = { > > &efi.mem_attr_table, > > }; > > > > +struct workqueue_struct *efi_rts_wq; > > + > > static bool disable_runtime; > > static int __init setup_noefi(char *arg) { @@ -329,6 +331,15 @@ > > static int __init efisubsys_init(void) > > if (!efi_enabled(EFI_BOOT)) > > return 0; > > > > + /* Create a work queue to run EFI Runtime Services */ > > + efi_rts_wq = create_workqueue("efi_rts_workqueue"); > > Please consider alloc_workqueue() instead with the appropriate flags, since > create_workqueue() and friends are deprecated. Sure! Will change in V2. > > > + if (!efi_rts_wq) { > > + pr_err("Failed to create efi_rts_workqueue, EFI runtime services " > > + "disabled.\n"); > > + clear_bit(EFI_RUNTIME_SERVICES, &efi.flags); > > + return 0; > > + } > > + > > /* > > * Clean DUMMY object calls EFI Runtime Service, set_variable(), so > > * it should be invoked only after efi_rts_workqueue is ready. > > diff --git a/drivers/firmware/efi/runtime-wrappers.c > > b/drivers/firmware/efi/runtime-wrappers.c > > index ae54870b2788..5cdb787da5d3 100644 > > --- a/drivers/firmware/efi/runtime-wrappers.c > > +++ b/drivers/firmware/efi/runtime-wrappers.c > > @@ -1,6 +1,14 @@ > > /* > > * runtime-wrappers.c - Runtime Services function call wrappers > > * > > + * Implementation summary: > > + * ----------------------- > > + * 1. When user/kernel thread requests to execute > > + efi_runtime_service(), > > + * enqueue work to efi_rts_workqueue. > > + * 2. Caller thread waits until the work is finished because it's > > + * dependent on the return status and execution of efi_runtime_service(). > > + * For instance, get_variable() and get_next_variable(). > > + * > > * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@xxxxxxxxxx> > > * > > * Split off from arch/x86/platform/efi/efi.c @@ -22,6 +30,8 @@ > > #include <linux/mutex.h> #include <linux/semaphore.h> #include > > <linux/stringify.h> > > +#include <linux/workqueue.h> > > + > > #include <asm/efi.h> > > > > /* > > @@ -33,6 +43,50 @@ > > #define __efi_call_virt(f, args...) \ > > __efi_call_virt_pointer(efi.systab->runtime, f, args) > > > > +/* Each EFI Runtime Service is represented with a unique number */ > > +#define GET_TIME 0 > > +#define SET_TIME 1 > > +#define GET_WAKEUP_TIME 2 > > +#define SET_WAKEUP_TIME 3 > > +#define GET_VARIABLE 4 > > +#define GET_NEXT_VARIABLE 5 > > +#define SET_VARIABLE 6 > > +#define SET_VARIABLE_NONBLOCKING 7 > > +#define QUERY_VARIABLE_INFO 8 > > +#define QUERY_VARIABLE_INFO_NONBLOCKING 9 > > +#define GET_NEXT_HIGH_MONO_COUNT 10 > > +#define RESET_SYSTEM 11 > > +#define UPDATE_CAPSULE 12 > > +#define QUERY_CAPSULE_CAPS 13 > > An enum would be better, given these are just internal, contiguous IDs. > Makes sense. > > + > > +/* > > + * efi_queue_work: Queue efi_runtime_service() and wait until it's done > > + * @rts: efi_runtime_service() function identifier > > + * @rts_arg<1-5>: efi_runtime_service() function arguments > > + * > > + * Accesses to efi_runtime_services() are serialized by a binary > > + * semaphore (efi_runtime_lock) and caller waits until the work is > > + * finished, hence _only_ one work is queued at a time. So, > > +queue_work() > > + * should never fail. > > + */ > > +#define efi_queue_work(_rts, _arg1, _arg2, _arg3, _arg4, _arg5) \ > > +({ \ > > + struct efi_runtime_work efi_rts_work; \ > > + efi_rts_work.status = EFI_ABORTED; \ > > + \ > > + INIT_WORK_ONSTACK(&efi_rts_work.work, efi_call_rts); \ > > + efi_rts_work.func = _rts; \ > > + efi_rts_work.arg1 = _arg1; \ > > + efi_rts_work.arg2 = _arg2; \ > > + efi_rts_work.arg3 = _arg3; \ > > + efi_rts_work.arg4 = _arg4; \ > > + efi_rts_work.arg5 = _arg5; \ > > + if (queue_work(efi_rts_wq, &efi_rts_work.work)) \ > > + flush_work(&efi_rts_work.work); \ > > If "So, queue_work() should never fail.", shouldn't this be a BUG() or similar? > BUG() sounds appropriate. Will roll it in V2. > > + \ > > + efi_rts_work.status; \ > > +}) > > + > > void efi_call_virt_check_flags(unsigned long flags, const char *call) > > { > > unsigned long cur_flags, mismatch; @@ -312,3 +366,92 @@ void > > efi_native_runtime_setup(void) > > efi.update_capsule = virt_efi_update_capsule; > > efi.query_capsule_caps = virt_efi_query_capsule_caps; } > > + > > +/* > > + * Calls the appropriate efi_runtime_service() with the appropriate > > + * arguments. > > + * > > + * Semantics followed by efi_call_rts() to understand efi_runtime_work: > > + * 1. If argument was a pointer, recast it from void pointer to > > +original > > + * pointer type. > > + * 2. If argument was a value, recast it from void pointer to > > +original > > + * pointer type and dereference it. > > + */ > > +void efi_call_rts(struct work_struct *work) { > > + struct efi_runtime_work *efi_rts_work; > > + void *arg1, *arg2, *arg3, *arg4, *arg5; > > + efi_status_t status = EFI_NOT_FOUND; > > + > > + efi_rts_work = container_of(work, struct efi_runtime_work, work); > > + arg1 = efi_rts_work->arg1; > > + arg2 = efi_rts_work->arg2; > > + arg3 = efi_rts_work->arg3; > > + arg4 = efi_rts_work->arg4; > > + arg5 = efi_rts_work->arg5; > > + > > + switch (efi_rts_work->func) { > > + case GET_TIME: > > + status = efi_call_virt(get_time, (efi_time_t *)arg1, > > + (efi_time_cap_t *)arg2); > > + break; > > + case SET_TIME: > > + status = efi_call_virt(set_time, (efi_time_t *)arg1); > > + break; > > + case GET_WAKEUP_TIME: > > + status = efi_call_virt(get_wakeup_time, (efi_bool_t *)arg1, > > + (efi_bool_t *)arg2, (efi_time_t *)arg3); > > + break; > > + case SET_WAKEUP_TIME: > > + status = efi_call_virt(set_wakeup_time, *(efi_bool_t *)arg1, > > + (efi_time_t *)arg2); > > + break; > > + case GET_VARIABLE: > > + status = efi_call_virt(get_variable, (efi_char16_t *)arg1, > > + (efi_guid_t *)arg2, (u32 *)arg3, > > + (unsigned long *)arg4, (void *)arg5); > > + break; > > + case GET_NEXT_VARIABLE: > > + status = efi_call_virt(get_next_variable, (unsigned long *)arg1, > > + (efi_char16_t *)arg2, > > + (efi_guid_t *)arg3); > > + break; > > + case SET_VARIABLE: > > + case SET_VARIABLE_NONBLOCKING: > > + status = efi_call_virt(set_variable, (efi_char16_t *)arg1, > > + (efi_guid_t *)arg2, *(u32 *)arg3, > > + *(unsigned long *)arg4, (void *)arg5); > > + break; > > + case QUERY_VARIABLE_INFO: > > + case QUERY_VARIABLE_INFO_NONBLOCKING: > > + status = efi_call_virt(query_variable_info, *(u32 *)arg1, > > + (u64 *)arg2, (u64 *)arg3, (u64 *)arg4); > > + break; > > + case GET_NEXT_HIGH_MONO_COUNT: > > + status = efi_call_virt(get_next_high_mono_count, (u32 *)arg1); > > + break; > > + case RESET_SYSTEM: > > + __efi_call_virt(reset_system, *(int *)arg1, > > + *(efi_status_t *)arg2, > > + *(unsigned long *)arg3, > > + (efi_char16_t *)arg4); > > + break; > > + case UPDATE_CAPSULE: > > + status = efi_call_virt(update_capsule, > > + (efi_capsule_header_t **)arg1, > > + *(unsigned long *)arg2, > > + *(unsigned long *)arg3); > > + break; > > + case QUERY_CAPSULE_CAPS: > > + status = efi_call_virt(query_capsule_caps, > > + (efi_capsule_header_t **)arg1, > > + *(unsigned long *)arg2, (u64 *)arg3, > > + (int *)arg4); > > + break; > > + default: > > + pr_err("Not a valid EFI_RT_SERVICE?"); > > + status = EFI_NOT_FOUND; > > + break; > > Given that efi_call_rts() is only called from the virt_efi_*() funtions in the same > file and that the IDs are internal as well, shouldn't this be a hard error? i.e. no > one should be calling this with an unknown ID at all. But please see below. That's true! No one should be calling with unknown ID. Will make it a BUG(). > > > + } > > + efi_rts_work->status = status; } > > diff --git a/include/linux/efi.h b/include/linux/efi.h index > > c4efb3ef0dfa..4abb401d40f5 100644 > > --- a/include/linux/efi.h > > +++ b/include/linux/efi.h > > @@ -1652,4 +1652,27 @@ struct linux_efi_tpm_eventlog { > > > > extern int efi_tpm_eventlog_init(void); > > > > +/* > > + * efi_runtime_work: Details of EFI Runtime Service work > > + * @func: EFI Runtime Service function identifier > > + * @arg<1-5>: EFI Runtime Service function arguments > > + * @status: Status of executing EFI Runtime Service > > + */ > > +struct efi_runtime_work { > > + u8 func; > > + void *arg1; > > + void *arg2; > > + void *arg3; > > + void *arg4; > > + void *arg5; > > + efi_status_t status; > > + struct work_struct work; > > +}; > > + > > +/* Workqueue to queue EFI Runtime Services */ extern struct > > +workqueue_struct *efi_rts_wq; > > + > > +/* Call back function that calls EFI Runtime Services */ extern void > > +efi_call_rts(struct work_struct *work); > > So this seems to indicate there will be external users calling > efi_call_rts() (even outside EFI itself, given it is in include/linux) > -- but then, how they will know what to put in "u8 func"? > My bad! efi_call_rts() should be static. There will not be any external users. > Note that I have no clue on EFI, so I am just commenting on how the patch > looks. :) > Thanks a lot! for the review. They are helpful :) Will make changes in V2. Regards, Sai ��.n��������+%������w��{.n�����{����*jg��������ݢj����G�������j:+v���w�m������w�������h�����٥