1139804Simp/*-
293835Stmm * Copyright (c) 1988 University of Utah.
393835Stmm * Copyright (c) 1982, 1990, 1993
4227723Slstewart *	The Regents of the University of California.
5227723Slstewart * Copyright (c) 2011 The FreeBSD Foundation
6227723Slstewart * All rights reserved.
793835Stmm *
893835Stmm * This code is derived from software contributed to Berkeley by
993835Stmm * the Systems Programming Group of the University of Utah Computer
1093835Stmm * Science Department.
1193835Stmm *
12227723Slstewart * Portions of this software were developed by Julien Ridoux at the University
13227723Slstewart * of Melbourne under sponsorship from the FreeBSD Foundation.
14227723Slstewart *
1593835Stmm * Redistribution and use in source and binary forms, with or without
1693835Stmm * modification, are permitted provided that the following conditions
1793835Stmm * are met:
1893835Stmm * 1. Redistributions of source code must retain the above copyright
1993835Stmm *    notice, this list of conditions and the following disclaimer.
2093835Stmm * 2. Redistributions in binary form must reproduce the above copyright
2193835Stmm *    notice, this list of conditions and the following disclaimer in the
2293835Stmm *    documentation and/or other materials provided with the distribution.
2393835Stmm * 4. Neither the name of the University nor the names of its contributors
2493835Stmm *    may be used to endorse or promote products derived from this software
2593835Stmm *    without specific prior written permission.
2693835Stmm *
2793835Stmm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2893835Stmm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2993835Stmm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3093835Stmm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3193835Stmm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3293835Stmm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3393835Stmm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3493835Stmm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3593835Stmm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3693835Stmm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3793835Stmm * SUCH DAMAGE.
3893835Stmm *
3993835Stmm *	from: Utah $Hdr: clock.c 1.18 91/01/21$
4093835Stmm *	from: @(#)clock.c	8.2 (Berkeley) 1/12/94
4193835Stmm *	from: NetBSD: clock_subr.c,v 1.6 2001/07/07 17:04:02 thorpej Exp
4293835Stmm *	and
4393835Stmm *	from: src/sys/i386/isa/clock.c,v 1.176 2001/09/04
4493835Stmm */
4593835Stmm
4693835Stmm/*
4793835Stmm * Helpers for time-of-day clocks. This is useful for architectures that need
4893835Stmm * support multiple models of such clocks, and generally serves to make the
4993835Stmm * code more machine-independent.
5093835Stmm * If the clock in question can also be used as a time counter, the driver
5193835Stmm * needs to initiate this.
5293835Stmm * This code is not yet used by all architectures.
5393835Stmm */
5493835Stmm
55116182Sobrien#include <sys/cdefs.h>
56116182Sobrien__FBSDID("$FreeBSD: stable/11/sys/kern/subr_rtc.c 338594 2018-09-11 18:35:08Z kib $");
57116182Sobrien
58227723Slstewart#include "opt_ffclock.h"
59227723Slstewart
6093835Stmm#include <sys/param.h>
6193835Stmm#include <sys/systm.h>
6293835Stmm#include <sys/kernel.h>
6393835Stmm#include <sys/bus.h>
6493835Stmm#include <sys/clock.h>
65302251Skib#include <sys/lock.h>
66323447Sian#include <sys/malloc.h>
67323447Sian#include <sys/sx.h>
6893835Stmm#include <sys/sysctl.h>
69323447Sian#include <sys/taskqueue.h>
70227723Slstewart#ifdef FFCLOCK
71227723Slstewart#include <sys/timeffc.h>
72227723Slstewart#endif
7393835Stmm#include <sys/timetc.h>
7493835Stmm
7593835Stmm#include "clock_if.h"
7693835Stmm
77331503Sianstatic int show_io;
78331503SianSYSCTL_INT(_debug, OID_AUTO, clock_show_io, CTLFLAG_RWTUN, &show_io, 0,
79331503Sian    "Enable debug printing of RTC clock I/O; 1=reads, 2=writes, 3=both.");
80331503Sian
81331503Sianstatic int sysctl_clock_do_io(SYSCTL_HANDLER_ARGS);
82331503SianSYSCTL_PROC(_debug, OID_AUTO, clock_do_io, CTLTYPE_INT | CTLFLAG_RW,
83331503Sian    0, 0, sysctl_clock_do_io, "I",
84331503Sian    "Trigger one-time IO on RTC clocks; 1=read (and discard), 2=write");
85331503Sian
86178429Sphk/* XXX: should be kern. now, it's no longer machdep.  */
87178429Sphkstatic int disable_rtc_set;
88211228SjkimSYSCTL_INT(_machdep, OID_AUTO, disable_rtc_set, CTLFLAG_RW, &disable_rtc_set,
89211228Sjkim    0, "Disallow adjusting time-of-day clock");
90178429Sphk
91323447Sian/*
92323447Sian * An instance of a realtime clock.  A list of these tracks all the registered
93323447Sian * clocks in the system.
94323447Sian *
95323447Sian * The resadj member is used to apply a "resolution adjustment" equal to half
96323447Sian * the clock's resolution, which is useful mainly on clocks with a whole-second
97323447Sian * resolution.  Because the clock truncates the fractional part, adding half the
98323447Sian * resolution performs 4/5 rounding.  The same adjustment is applied to the
99323447Sian * times returned from clock_gettime(), because the fraction returned will
100323447Sian * always be zero, but on average the actual fraction at the time of the call
101323447Sian * should be about .5.
102323447Sian */
103323447Sianstruct rtc_instance {
104323447Sian	device_t	clockdev;
105323447Sian	int		resolution;
106323447Sian	int		flags;
107323447Sian	u_int		schedns;
108323447Sian	struct timespec resadj;
109323447Sian	struct timeout_task
110323447Sian			stask;
111323447Sian	LIST_ENTRY(rtc_instance)
112323447Sian			rtc_entries;
113323447Sian};
114323447Sian
115323447Sian/*
116323447Sian * Clocks are updated using a task running on taskqueue_thread.
117323447Sian */
118323447Sianstatic void settime_task_func(void *arg, int pending);
119323447Sian
120323447Sian/*
121323447Sian * Registered clocks are kept in a list which is sorted by resolution; the more
122323447Sian * accurate clocks get the first shot at providing the time.
123323447Sian */
124323447SianLIST_HEAD(rtc_listhead, rtc_instance);
125323447Sianstatic struct rtc_listhead rtc_list = LIST_HEAD_INITIALIZER(rtc_list);
126323447Sianstatic struct sx rtc_list_lock;
127323447SianSX_SYSINIT(rtc_list_lock_init, &rtc_list_lock, "rtc list");
128323447Sian
129323447Sian/*
130323447Sian * On the task thread, invoke the clock_settime() method of the clock.  Do so
131323447Sian * holding no locks, so that clock drivers are free to do whatever kind of
132323447Sian * locking or sleeping they need to.
133323447Sian */
134323447Sianstatic void
135323447Siansettime_task_func(void *arg, int pending)
136323447Sian{
137323447Sian	struct timespec ts;
138323447Sian	struct rtc_instance *rtc;
139338594Skib	int error;
140323447Sian
141323447Sian	rtc = arg;
142323447Sian	if (!(rtc->flags & CLOCKF_SETTIME_NO_TS)) {
143323447Sian		getnanotime(&ts);
144323447Sian		if (!(rtc->flags & CLOCKF_SETTIME_NO_ADJ)) {
145323447Sian			ts.tv_sec -= utc_offset();
146323447Sian			timespecadd(&ts, &rtc->resadj);
147323447Sian		}
148323447Sian	} else {
149323447Sian		ts.tv_sec  = 0;
150323447Sian		ts.tv_nsec = 0;
151323447Sian	}
152338594Skib	error = CLOCK_SETTIME(rtc->clockdev, &ts);
153338594Skib	if (error != 0 && bootverbose)
154338594Skib		device_printf(rtc->clockdev, "CLOCK_SETTIME error %d\n", error);
155323447Sian}
156323447Sian
157331503Sianstatic void
158331503Sianclock_dbgprint_hdr(device_t dev, int rw)
159331503Sian{
160331503Sian	struct timespec now;
161331503Sian
162331503Sian	getnanotime(&now);
163331503Sian	device_printf(dev, "%s at ", (rw & CLOCK_DBG_READ) ? "read " : "write");
164331503Sian	clock_print_ts(&now, 9);
165331503Sian	printf(": ");
166331503Sian}
167331503Sian
16893835Stmmvoid
169331503Sianclock_dbgprint_bcd(device_t dev, int rw, const struct bcd_clocktime *bct)
170331503Sian{
171331503Sian
172331503Sian	if (show_io & rw) {
173331503Sian		clock_dbgprint_hdr(dev, rw);
174331503Sian		clock_print_bcd(bct, 9);
175331503Sian		printf("\n");
176331503Sian	}
177331503Sian}
178331503Sian
179331503Sianvoid
180331503Sianclock_dbgprint_ct(device_t dev, int rw, const struct clocktime *ct)
181331503Sian{
182331503Sian
183331503Sian	if (show_io & rw) {
184331503Sian		clock_dbgprint_hdr(dev, rw);
185331503Sian		clock_print_ct(ct, 9);
186331503Sian		printf("\n");
187331503Sian	}
188331503Sian}
189331503Sian
190331503Sianvoid
191331503Sianclock_dbgprint_err(device_t dev, int rw, int err)
192331503Sian{
193331503Sian
194331503Sian	if (show_io & rw) {
195331503Sian		clock_dbgprint_hdr(dev, rw);
196331503Sian		printf("error = %d\n", err);
197331503Sian	}
198331503Sian}
199331503Sian
200331503Sianvoid
201331503Sianclock_dbgprint_ts(device_t dev, int rw, const struct timespec *ts)
202331503Sian{
203331503Sian
204331503Sian	if (show_io & rw) {
205331503Sian		clock_dbgprint_hdr(dev, rw);
206331503Sian		clock_print_ts(ts, 9);
207331503Sian		printf("\n");
208331503Sian	}
209331503Sian}
210331503Sian
211331503Sianvoid
212323447Sianclock_register_flags(device_t clockdev, long resolution, int flags)
21393835Stmm{
214323447Sian	struct rtc_instance *rtc, *newrtc;
21593835Stmm
216323447Sian	newrtc = malloc(sizeof(*newrtc), M_DEVBUF, M_WAITOK);
217323447Sian	newrtc->clockdev = clockdev;
218323447Sian	newrtc->resolution = (int)resolution;
219323447Sian	newrtc->flags = flags;
220323447Sian	newrtc->schedns = 0;
221323447Sian	newrtc->resadj.tv_sec  = newrtc->resolution / 2 / 1000000;
222323447Sian	newrtc->resadj.tv_nsec = newrtc->resolution / 2 % 1000000 * 1000;
223323447Sian	TIMEOUT_TASK_INIT(taskqueue_thread, &newrtc->stask, 0,
224323447Sian		    settime_task_func, newrtc);
225323447Sian
226323447Sian	sx_xlock(&rtc_list_lock);
227323447Sian	if (LIST_EMPTY(&rtc_list)) {
228323447Sian		LIST_INSERT_HEAD(&rtc_list, newrtc, rtc_entries);
229323447Sian	} else {
230323447Sian		LIST_FOREACH(rtc, &rtc_list, rtc_entries) {
231323447Sian			if (rtc->resolution > newrtc->resolution) {
232323447Sian				LIST_INSERT_BEFORE(rtc, newrtc, rtc_entries);
233323447Sian				break;
234323447Sian			} else if (LIST_NEXT(rtc, rtc_entries) == NULL) {
235323447Sian				LIST_INSERT_AFTER(rtc, newrtc, rtc_entries);
236323447Sian				break;
237323447Sian			}
23893835Stmm		}
23993835Stmm	}
240323447Sian	sx_xunlock(&rtc_list_lock);
241323447Sian
242323447Sian	device_printf(clockdev,
243323447Sian	    "registered as a time-of-day clock, resolution %d.%6.6ds\n",
244323447Sian	    newrtc->resolution / 1000000, newrtc->resolution % 1000000);
24593835Stmm}
24693835Stmm
247323447Sianvoid
248323447Sianclock_register(device_t dev, long res)
249323447Sian{
25093835Stmm
251323447Sian	clock_register_flags(dev, res, 0);
252323447Sian}
253323447Sian
254323447Sianvoid
255323447Sianclock_unregister(device_t clockdev)
256323447Sian{
257323447Sian	struct rtc_instance *rtc, *tmp;
258323447Sian
259323447Sian	sx_xlock(&rtc_list_lock);
260323447Sian	LIST_FOREACH_SAFE(rtc, &rtc_list, rtc_entries, tmp) {
261323447Sian		if (rtc->clockdev == clockdev) {
262323447Sian			LIST_REMOVE(rtc, rtc_entries);
263323447Sian			break;
264323447Sian		}
265323447Sian	}
266323447Sian	sx_xunlock(&rtc_list_lock);
267323447Sian	if (rtc != NULL) {
268323447Sian		taskqueue_cancel_timeout(taskqueue_thread, &rtc->stask, NULL);
269323447Sian		taskqueue_drain_timeout(taskqueue_thread, &rtc->stask);
270331503Sian		free(rtc, M_DEVBUF);
271323447Sian	}
272323447Sian}
273323447Sian
274323447Sianvoid
275323447Sianclock_schedule(device_t clockdev, u_int offsetns)
276323447Sian{
277323447Sian	struct rtc_instance *rtc;
278323447Sian
279323447Sian	sx_xlock(&rtc_list_lock);
280323447Sian	LIST_FOREACH(rtc, &rtc_list, rtc_entries) {
281323447Sian		if (rtc->clockdev == clockdev) {
282323447Sian			rtc->schedns = offsetns;
283323447Sian			break;
284323447Sian		}
285323447Sian	}
286323447Sian	sx_xunlock(&rtc_list_lock);
287323447Sian}
288323447Sian
289331503Sianstatic int
290331503Sianread_clocks(struct timespec *ts, bool debug_read)
291331503Sian{
292331503Sian	struct rtc_instance *rtc;
293331503Sian	int error;
294331503Sian
295331503Sian	error = ENXIO;
296331503Sian	sx_xlock(&rtc_list_lock);
297331503Sian	LIST_FOREACH(rtc, &rtc_list, rtc_entries) {
298331503Sian		if ((error = CLOCK_GETTIME(rtc->clockdev, ts)) != 0)
299331503Sian			continue;
300331503Sian		if (ts->tv_sec < 0 || ts->tv_nsec < 0) {
301331503Sian			error = EINVAL;
302331503Sian			continue;
303331503Sian		}
304331503Sian		if (!(rtc->flags & CLOCKF_GETTIME_NO_ADJ)) {
305331503Sian			timespecadd(ts, &rtc->resadj);
306331503Sian			ts->tv_sec += utc_offset();
307331503Sian		}
308331503Sian		if (!debug_read) {
309331503Sian			if (bootverbose)
310331503Sian				device_printf(rtc->clockdev,
311331503Sian				    "providing initial system time\n");
312331503Sian			break;
313331503Sian		}
314331503Sian	}
315331503Sian	sx_xunlock(&rtc_list_lock);
316331503Sian	return (error);
317331503Sian}
318331503Sian
31993835Stmm/*
320323447Sian * Initialize the system time.  Must be called from a context which does not
321323447Sian * restrict any locking or sleeping that clock drivers may need to do.
322323447Sian *
323323447Sian * First attempt to get the time from a registered realtime clock.  The clocks
324323447Sian * are queried in order of resolution until one provides the time.  If no clock
325323447Sian * can provide the current time, use the 'base' time provided by the caller, if
326323447Sian * non-zero.  The 'base' time is potentially highly inaccurate, such as the last
327323447Sian * known good value of the system clock, or even a filesystem last-updated
328323447Sian * timestamp.  It is used to prevent system time from appearing to move
329323447Sian * backwards in logs.
33093835Stmm */
33193835Stmmvoid
33293835Stmminittodr(time_t base)
33393835Stmm{
334211228Sjkim	struct timespec ts;
33593835Stmm	int error;
33693835Stmm
337331503Sian	error = read_clocks(&ts, false);
338323447Sian
339323447Sian	/*
340323447Sian	 * Do not report errors from each clock; it is expected that some clocks
341323447Sian	 * cannot provide results in some situations.  Only report problems when
342323447Sian	 * no clocks could provide the time.
343323447Sian	 */
344323447Sian	if (error != 0) {
345323447Sian		switch (error) {
346323447Sian		case ENXIO:
347323447Sian			printf("Warning: no time-of-day clock registered, ");
348323447Sian			break;
349323447Sian		case EINVAL:
350323447Sian			printf("Warning: bad time from time-of-day clock, ");
351323447Sian			break;
352323447Sian		default:
353323447Sian			printf("Error reading time-of-day clock (%d), ", error);
354323447Sian			break;
355323447Sian		}
356323447Sian		printf("system time will not be set accurately\n");
357323447Sian		ts.tv_sec  = (base > 0) ? base : -1;
358323447Sian		ts.tv_nsec = 0;
35993835Stmm	}
36093835Stmm
361323447Sian	if (ts.tv_sec >= 0) {
362323447Sian		tc_setclock(&ts);
363227723Slstewart#ifdef FFCLOCK
364323447Sian		ffclock_reset_clock(&ts);
365227723Slstewart#endif
36693835Stmm	}
36793835Stmm}
36893835Stmm
36993835Stmm/*
370323447Sian * Write system time back to all registered clocks, unless disabled by admin.
371323447Sian * This can be called from a context that restricts locking and/or sleeping; the
372323447Sian * actual updating is done asynchronously on a task thread.
37393835Stmm */
37493835Stmmvoid
375188055Simpresettodr(void)
37693835Stmm{
377323447Sian	struct timespec now;
378323447Sian	struct rtc_instance *rtc;
379323447Sian	sbintime_t sbt;
380323447Sian	long waitns;
38193835Stmm
382323447Sian	if (disable_rtc_set)
38393835Stmm		return;
38493835Stmm
385323447Sian	sx_xlock(&rtc_list_lock);
386323447Sian	LIST_FOREACH(rtc, &rtc_list, rtc_entries) {
387323447Sian		if (rtc->schedns != 0) {
388323447Sian			getnanotime(&now);
389323447Sian			waitns = rtc->schedns - now.tv_nsec;
390323447Sian			if (waitns < 0)
391323447Sian				waitns += 1000000000;
392323447Sian			sbt = nstosbt(waitns);
393323447Sian		} else
394323447Sian			sbt = 0;
395323447Sian		taskqueue_enqueue_timeout_sbt(taskqueue_thread,
396323447Sian		    &rtc->stask, -sbt, 0, C_PREL(31));
397323447Sian	}
398323447Sian	sx_xunlock(&rtc_list_lock);
39993835Stmm}
400331503Sian
401331503Sianstatic int
402331503Siansysctl_clock_do_io(SYSCTL_HANDLER_ARGS)
403331503Sian{
404331503Sian	struct timespec ts_discard;
405331503Sian	int error, value;
406331503Sian
407331503Sian	value = 0;
408331503Sian	error = sysctl_handle_int(oidp, &value, 0, req);
409331503Sian	if (error != 0 || req->newptr == NULL)
410331503Sian		return (error);
411331503Sian
412331503Sian	switch (value) {
413331503Sian	case CLOCK_DBG_READ:
414331503Sian		if (read_clocks(&ts_discard, true) == ENXIO)
415331503Sian			printf("No registered RTC clocks\n");
416331503Sian		break;
417331503Sian	case CLOCK_DBG_WRITE:
418331503Sian		resettodr();
419331503Sian		break;
420331503Sian	default:
421331503Sian                return (EINVAL);
422331503Sian	}
423331503Sian
424331503Sian	return (0);
425331503Sian}
426