Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Jan Beulich and committed by
Ingo Molnar
ef68c8f8 ac619f4e

+33 -6
+33 -6
arch/x86/platform/efi/efi.c
··· 79 79 80 80 static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) 81 81 { 82 - return efi_call_virt2(get_time, tm, tc); 82 + unsigned long flags; 83 + efi_status_t status; 84 + 85 + spin_lock_irqsave(&rtc_lock, flags); 86 + status = efi_call_virt2(get_time, tm, tc); 87 + spin_unlock_irqrestore(&rtc_lock, flags); 88 + return status; 83 89 } 84 90 85 91 static efi_status_t virt_efi_set_time(efi_time_t *tm) 86 92 { 87 - return efi_call_virt1(set_time, tm); 93 + unsigned long flags; 94 + efi_status_t status; 95 + 96 + spin_lock_irqsave(&rtc_lock, flags); 97 + status = efi_call_virt1(set_time, tm); 98 + spin_unlock_irqrestore(&rtc_lock, flags); 99 + return status; 88 100 } 89 101 90 102 static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled, 91 103 efi_bool_t *pending, 92 104 efi_time_t *tm) 93 105 { 94 - return efi_call_virt3(get_wakeup_time, 95 - enabled, pending, tm); 106 + unsigned long flags; 107 + efi_status_t status; 108 + 109 + spin_lock_irqsave(&rtc_lock, flags); 110 + status = efi_call_virt3(get_wakeup_time, 111 + enabled, pending, tm); 112 + spin_unlock_irqrestore(&rtc_lock, flags); 113 + return status; 96 114 } 97 115 98 116 static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) 99 117 { 100 - return efi_call_virt2(set_wakeup_time, 101 - enabled, tm); 118 + unsigned long flags; 119 + efi_status_t status; 120 + 121 + spin_lock_irqsave(&rtc_lock, flags); 122 + status = efi_call_virt2(set_wakeup_time, 123 + enabled, tm); 124 + spin_unlock_irqrestore(&rtc_lock, flags); 125 + return status; 102 126 } 103 127 104 128 static efi_status_t virt_efi_get_variable(efi_char16_t *name, ··· 188 164 static efi_status_t __init phys_efi_get_time(efi_time_t *tm, 189 165 efi_time_cap_t *tc) 190 166 { 167 + unsigned long flags; 191 168 efi_status_t status; 192 169 170 + spin_lock_irqsave(&rtc_lock, flags); 193 171 efi_call_phys_prelog(); 194 172 status = efi_call_phys2(efi_phys.get_time, tm, tc); 195 173 efi_call_phys_epilog(); 174 + spin_unlock_irqrestore(&rtc_lock, flags); 196 175 return status; 197 176 } 198 177