Add a new sysctl, debug.clock_do_io, to allow manully triggering a one-shot

read or write of all registered realtime clocks.  In the read case, the
values read are simply discarded.  For writes, there's no alternative but
to actually write the current system time to the device.
This commit is contained in:
Ian Lepore 2018-02-12 17:41:11 +00:00
parent 45eee6db6f
commit bd54c5acba
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=329173

View File

@ -80,6 +80,11 @@ static int show_io;
SYSCTL_INT(_debug, OID_AUTO, clock_show_io, CTLFLAG_RWTUN, &show_io, 0,
"Enable debug printing of RTC clock I/O; 1=reads, 2=writes, 3=both.");
static int sysctl_clock_do_io(SYSCTL_HANDLER_ARGS);
SYSCTL_PROC(_debug, OID_AUTO, clock_do_io, CTLTYPE_INT | CTLFLAG_RW,
0, 0, sysctl_clock_do_io, "I",
"Trigger one-time IO on RTC clocks; 1=read (and discard), 2=write");
/* XXX: should be kern. now, it's no longer machdep. */
static int disable_rtc_set;
SYSCTL_INT(_machdep, OID_AUTO, disable_rtc_set, CTLFLAG_RW, &disable_rtc_set,
@ -280,6 +285,36 @@ clock_schedule(device_t clockdev, u_int offsetns)
sx_xunlock(&rtc_list_lock);
}
static int
read_clocks(struct timespec *ts, bool debug_read)
{
struct rtc_instance *rtc;
int error;
error = ENXIO;
sx_xlock(&rtc_list_lock);
LIST_FOREACH(rtc, &rtc_list, rtc_entries) {
if ((error = CLOCK_GETTIME(rtc->clockdev, ts)) != 0)
continue;
if (ts->tv_sec < 0 || ts->tv_nsec < 0) {
error = EINVAL;
continue;
}
if (!(rtc->flags & CLOCKF_GETTIME_NO_ADJ)) {
timespecadd(ts, &rtc->resadj);
ts->tv_sec += utc_offset();
}
if (!debug_read) {
if (bootverbose)
device_printf(rtc->clockdev,
"providing initial system time\n");
break;
}
}
sx_xunlock(&rtc_list_lock);
return (error);
}
/*
* Initialize the system time. Must be called from a context which does not
* restrict any locking or sleeping that clock drivers may need to do.
@ -296,28 +331,9 @@ void
inittodr(time_t base)
{
struct timespec ts;
struct rtc_instance *rtc;
int error;
error = ENXIO;
sx_xlock(&rtc_list_lock);
LIST_FOREACH(rtc, &rtc_list, rtc_entries) {
if ((error = CLOCK_GETTIME(rtc->clockdev, &ts)) != 0)
continue;
if (ts.tv_sec < 0 || ts.tv_nsec < 0) {
error = EINVAL;
continue;
}
if (!(rtc->flags & CLOCKF_GETTIME_NO_ADJ)) {
timespecadd(&ts, &rtc->resadj);
ts.tv_sec += utc_offset();
}
if (bootverbose)
device_printf(rtc->clockdev,
"providing initial system time\n");
break;
}
sx_xunlock(&rtc_list_lock);
error = read_clocks(&ts, false);
/*
* Do not report errors from each clock; it is expected that some clocks
@ -380,3 +396,29 @@ resettodr(void)
}
sx_xunlock(&rtc_list_lock);
}
static int
sysctl_clock_do_io(SYSCTL_HANDLER_ARGS)
{
struct timespec ts_discard;
int error, value;
value = 0;
error = sysctl_handle_int(oidp, &value, 0, req);
if (error != 0 || req->newptr == NULL)
return (error);
switch (value) {
case CLOCK_DBG_READ:
if (read_clocks(&ts_discard, true) == ENXIO)
printf("No registered RTC clocks\n");
break;
case CLOCK_DBG_WRITE:
resettodr();
break;
default:
return (EINVAL);
}
return (0);
}