Protect access to the AT realtime clock with its own mutex.
The mutex protecting access to the registered realtime clock should not be overloaded to protect access to the atrtc hardware, which might not even be the registered rtc. More importantly, the resettodr mutex needs to be eliminated to remove locking/sleeping restrictions on clock drivers, and that can't happen if MD code for amd64 depends on it. This change moves the protection into what's really being protected: access to the atrtc date and time registers. This change also adds protection when the clock is accessed from xentimer_settime(), which bypasses the resettodr locking. Differential Revision: https://reviews.freebsd.org/D11483
This commit is contained in:
parent
b4c54ab330
commit
242599409b
@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/vmmeter.h>
|
||||
#include <isa/rtc.h>
|
||||
#include <machine/fpu.h>
|
||||
#include <machine/efi.h>
|
||||
#include <machine/metadata.h>
|
||||
@ -445,7 +446,7 @@ efi_get_time_locked(struct efi_tm *tm)
|
||||
efi_status status;
|
||||
int error;
|
||||
|
||||
mtx_assert(&resettodr_lock, MA_OWNED);
|
||||
mtx_assert(&atrtc_time_lock, MA_OWNED);
|
||||
error = efi_enter();
|
||||
if (error != 0)
|
||||
return (error);
|
||||
@ -462,9 +463,9 @@ efi_get_time(struct efi_tm *tm)
|
||||
|
||||
if (efi_runtime == NULL)
|
||||
return (ENXIO);
|
||||
mtx_lock(&resettodr_lock);
|
||||
mtx_lock(&atrtc_time_lock);
|
||||
error = efi_get_time_locked(tm);
|
||||
mtx_unlock(&resettodr_lock);
|
||||
mtx_unlock(&atrtc_time_lock);
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -487,7 +488,7 @@ efi_set_time_locked(struct efi_tm *tm)
|
||||
efi_status status;
|
||||
int error;
|
||||
|
||||
mtx_assert(&resettodr_lock, MA_OWNED);
|
||||
mtx_assert(&atrtc_time_lock, MA_OWNED);
|
||||
error = efi_enter();
|
||||
if (error != 0)
|
||||
return (error);
|
||||
@ -504,9 +505,9 @@ efi_set_time(struct efi_tm *tm)
|
||||
|
||||
if (efi_runtime == NULL)
|
||||
return (ENXIO);
|
||||
mtx_lock(&resettodr_lock);
|
||||
mtx_lock(&atrtc_time_lock);
|
||||
error = efi_set_time_locked(tm);
|
||||
mtx_unlock(&resettodr_lock);
|
||||
mtx_unlock(&atrtc_time_lock);
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
@ -113,6 +113,7 @@
|
||||
|
||||
#ifdef _KERNEL
|
||||
extern struct mtx clock_lock;
|
||||
extern struct mtx atrtc_time_lock;
|
||||
extern int atrtcclock_disable;
|
||||
int rtcin(int reg);
|
||||
void atrtc_restore(void);
|
||||
|
@ -53,9 +53,17 @@ __FBSDID("$FreeBSD$");
|
||||
#include <machine/intr_machdep.h>
|
||||
#include "clock_if.h"
|
||||
|
||||
/*
|
||||
* clock_lock protects low-level access to individual hardware registers.
|
||||
* atrtc_time_lock protects the entire sequence of accessing multiple registers
|
||||
* to read or write the date and time.
|
||||
*/
|
||||
#define RTC_LOCK do { if (!kdb_active) mtx_lock_spin(&clock_lock); } while (0)
|
||||
#define RTC_UNLOCK do { if (!kdb_active) mtx_unlock_spin(&clock_lock); } while (0)
|
||||
|
||||
struct mtx atrtc_time_lock;
|
||||
MTX_SYSINIT(atrtc_lock_init, &atrtc_time_lock, "atrtc", MTX_DEF);
|
||||
|
||||
int atrtcclock_disable = 0;
|
||||
|
||||
static int rtc_reg = -1;
|
||||
@ -163,6 +171,8 @@ atrtc_set(struct timespec *ts)
|
||||
|
||||
clock_ts_to_ct(ts, &ct);
|
||||
|
||||
mtx_lock(&atrtc_time_lock);
|
||||
|
||||
/* Disable RTC updates and interrupts. */
|
||||
writertc(RTC_STATUSB, RTCSB_HALT | RTCSB_24HR);
|
||||
|
||||
@ -181,6 +191,8 @@ atrtc_set(struct timespec *ts)
|
||||
/* Re-enable RTC updates and interrupts. */
|
||||
writertc(RTC_STATUSB, rtc_statusb);
|
||||
rtcin(RTC_INTR);
|
||||
|
||||
mtx_unlock(&atrtc_time_lock);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
@ -352,6 +364,7 @@ atrtc_gettime(device_t dev, struct timespec *ts)
|
||||
* to make sure that no more than 240us pass after we start reading,
|
||||
* and try again if so.
|
||||
*/
|
||||
mtx_lock(&atrtc_time_lock);
|
||||
while (rtcin(RTC_STATUSA) & RTCSA_TUP)
|
||||
continue;
|
||||
critical_enter();
|
||||
@ -369,6 +382,7 @@ atrtc_gettime(device_t dev, struct timespec *ts)
|
||||
ct.year += (ct.year < 80 ? 2000 : 1900);
|
||||
#endif
|
||||
critical_exit();
|
||||
mtx_unlock(&atrtc_time_lock);
|
||||
/* Set dow = -1 because some clocks don't set it correctly. */
|
||||
ct.dow = -1;
|
||||
return (clock_ct_to_ts(&ct, ts));
|
||||
|
Loading…
Reference in New Issue
Block a user