Date: Wed, 12 Jul 2017 02:42:57 +0000 (UTC) From: Ian Lepore <ian@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r320901 - in head/sys: amd64/amd64 isa x86/isa Message-ID: <201707120242.v6C2gvDB026199@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: ian Date: Wed Jul 12 02:42:57 2017 New Revision: 320901 URL: https://svnweb.freebsd.org/changeset/base/320901 Log: 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 Modified: head/sys/amd64/amd64/efirt.c head/sys/isa/rtc.h head/sys/x86/isa/atrtc.c Modified: head/sys/amd64/amd64/efirt.c ============================================================================== --- head/sys/amd64/amd64/efirt.c Tue Jul 11 21:55:20 2017 (r320900) +++ head/sys/amd64/amd64/efirt.c Wed Jul 12 02:42:57 2017 (r320901) @@ -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); } Modified: head/sys/isa/rtc.h ============================================================================== --- head/sys/isa/rtc.h Tue Jul 11 21:55:20 2017 (r320900) +++ head/sys/isa/rtc.h Wed Jul 12 02:42:57 2017 (r320901) @@ -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); Modified: head/sys/x86/isa/atrtc.c ============================================================================== --- head/sys/x86/isa/atrtc.c Tue Jul 11 21:55:20 2017 (r320900) +++ head/sys/x86/isa/atrtc.c Wed Jul 12 02:42:57 2017 (r320901) @@ -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));
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201707120242.v6C2gvDB026199>