x86: Serialize EFI time accesses on rtc_lock
The EFI specification requires that callers of the time related runtime functions serialize with other CMOS accesses in the kernel, as the EFI time functions may choose to also use the legacy CMOS RTC. Besides fixing a latent bug, this is a prerequisite to safely enable the rtc-efi driver for x86, which ought to be preferred over rtc-cmos on all EFI platforms. Signed-off-by: Jan Beulich <jbeulich@novell.com> Acked-by: Matthew Garrett <mjg59@srcf.ucam.org> Cc: <mjg@redhat.com> Link: http://lkml.kernel.org/r/4E257E33020000780004E319@nat28.tlf.novell.com Signed-off-by: Ingo Molnar <mingo@elte.hu> Cc: Matthew Garrett <mjg@redhat.com>
This commit is contained in:
parent
ac619f4eba
commit
ef68c8f87e
1 changed files with 33 additions and 6 deletions
|
@ -79,26 +79,50 @@ early_param("add_efi_memmap", setup_add_efi_memmap);
|
|||
|
||||
static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
|
||||
{
|
||||
return efi_call_virt2(get_time, tm, tc);
|
||||
unsigned long flags;
|
||||
efi_status_t status;
|
||||
|
||||
spin_lock_irqsave(&rtc_lock, flags);
|
||||
status = efi_call_virt2(get_time, tm, tc);
|
||||
spin_unlock_irqrestore(&rtc_lock, flags);
|
||||
return status;
|
||||
}
|
||||
|
||||
static efi_status_t virt_efi_set_time(efi_time_t *tm)
|
||||
{
|
||||
return efi_call_virt1(set_time, tm);
|
||||
unsigned long flags;
|
||||
efi_status_t status;
|
||||
|
||||
spin_lock_irqsave(&rtc_lock, flags);
|
||||
status = efi_call_virt1(set_time, tm);
|
||||
spin_unlock_irqrestore(&rtc_lock, flags);
|
||||
return status;
|
||||
}
|
||||
|
||||
static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled,
|
||||
efi_bool_t *pending,
|
||||
efi_time_t *tm)
|
||||
{
|
||||
return efi_call_virt3(get_wakeup_time,
|
||||
enabled, pending, tm);
|
||||
unsigned long flags;
|
||||
efi_status_t status;
|
||||
|
||||
spin_lock_irqsave(&rtc_lock, flags);
|
||||
status = efi_call_virt3(get_wakeup_time,
|
||||
enabled, pending, tm);
|
||||
spin_unlock_irqrestore(&rtc_lock, flags);
|
||||
return status;
|
||||
}
|
||||
|
||||
static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
|
||||
{
|
||||
return efi_call_virt2(set_wakeup_time,
|
||||
enabled, tm);
|
||||
unsigned long flags;
|
||||
efi_status_t status;
|
||||
|
||||
spin_lock_irqsave(&rtc_lock, flags);
|
||||
status = efi_call_virt2(set_wakeup_time,
|
||||
enabled, tm);
|
||||
spin_unlock_irqrestore(&rtc_lock, flags);
|
||||
return status;
|
||||
}
|
||||
|
||||
static efi_status_t virt_efi_get_variable(efi_char16_t *name,
|
||||
|
@ -164,11 +188,14 @@ static efi_status_t __init phys_efi_set_virtual_address_map(
|
|||
static efi_status_t __init phys_efi_get_time(efi_time_t *tm,
|
||||
efi_time_cap_t *tc)
|
||||
{
|
||||
unsigned long flags;
|
||||
efi_status_t status;
|
||||
|
||||
spin_lock_irqsave(&rtc_lock, flags);
|
||||
efi_call_phys_prelog();
|
||||
status = efi_call_phys2(efi_phys.get_time, tm, tc);
|
||||
efi_call_phys_epilog();
|
||||
spin_unlock_irqrestore(&rtc_lock, flags);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue