subr_rtc.c (330897) | subr_rtc.c (331503) |
---|---|
1/*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1988 University of Utah. 5 * Copyright (c) 1982, 1990, 1993 6 * The Regents of the University of California. 7 * Copyright (c) 2011 The FreeBSD Foundation 8 * All rights reserved. --- 41 unchanged lines hidden (view full) --- 50 * support multiple models of such clocks, and generally serves to make the 51 * code more machine-independent. 52 * If the clock in question can also be used as a time counter, the driver 53 * needs to initiate this. 54 * This code is not yet used by all architectures. 55 */ 56 57#include <sys/cdefs.h> | 1/*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1988 University of Utah. 5 * Copyright (c) 1982, 1990, 1993 6 * The Regents of the University of California. 7 * Copyright (c) 2011 The FreeBSD Foundation 8 * All rights reserved. --- 41 unchanged lines hidden (view full) --- 50 * support multiple models of such clocks, and generally serves to make the 51 * code more machine-independent. 52 * If the clock in question can also be used as a time counter, the driver 53 * needs to initiate this. 54 * This code is not yet used by all architectures. 55 */ 56 57#include <sys/cdefs.h> |
58__FBSDID("$FreeBSD: stable/11/sys/kern/subr_rtc.c 330897 2018-03-14 03:19:51Z eadler $"); | 58__FBSDID("$FreeBSD: stable/11/sys/kern/subr_rtc.c 331503 2018-03-24 23:01:10Z ian $"); |
59 60#include "opt_ffclock.h" 61 62#include <sys/param.h> 63#include <sys/systm.h> 64#include <sys/kernel.h> 65#include <sys/bus.h> 66#include <sys/clock.h> --- 4 unchanged lines hidden (view full) --- 71#include <sys/taskqueue.h> 72#ifdef FFCLOCK 73#include <sys/timeffc.h> 74#endif 75#include <sys/timetc.h> 76 77#include "clock_if.h" 78 | 59 60#include "opt_ffclock.h" 61 62#include <sys/param.h> 63#include <sys/systm.h> 64#include <sys/kernel.h> 65#include <sys/bus.h> 66#include <sys/clock.h> --- 4 unchanged lines hidden (view full) --- 71#include <sys/taskqueue.h> 72#ifdef FFCLOCK 73#include <sys/timeffc.h> 74#endif 75#include <sys/timetc.h> 76 77#include "clock_if.h" 78 |
79static int show_io; 80SYSCTL_INT(_debug, OID_AUTO, clock_show_io, CTLFLAG_RWTUN, &show_io, 0, 81 "Enable debug printing of RTC clock I/O; 1=reads, 2=writes, 3=both."); 82 83static int sysctl_clock_do_io(SYSCTL_HANDLER_ARGS); 84SYSCTL_PROC(_debug, OID_AUTO, clock_do_io, CTLTYPE_INT | CTLFLAG_RW, 85 0, 0, sysctl_clock_do_io, "I", 86 "Trigger one-time IO on RTC clocks; 1=read (and discard), 2=write"); 87 |
|
79/* XXX: should be kern. now, it's no longer machdep. */ 80static int disable_rtc_set; 81SYSCTL_INT(_machdep, OID_AUTO, disable_rtc_set, CTLFLAG_RW, &disable_rtc_set, 82 0, "Disallow adjusting time-of-day clock"); 83 84/* 85 * An instance of a realtime clock. A list of these tracks all the registered 86 * clocks in the system. --- 52 unchanged lines hidden (view full) --- 139 } 140 } else { 141 ts.tv_sec = 0; 142 ts.tv_nsec = 0; 143 } 144 CLOCK_SETTIME(rtc->clockdev, &ts); 145} 146 | 88/* XXX: should be kern. now, it's no longer machdep. */ 89static int disable_rtc_set; 90SYSCTL_INT(_machdep, OID_AUTO, disable_rtc_set, CTLFLAG_RW, &disable_rtc_set, 91 0, "Disallow adjusting time-of-day clock"); 92 93/* 94 * An instance of a realtime clock. A list of these tracks all the registered 95 * clocks in the system. --- 52 unchanged lines hidden (view full) --- 148 } 149 } else { 150 ts.tv_sec = 0; 151 ts.tv_nsec = 0; 152 } 153 CLOCK_SETTIME(rtc->clockdev, &ts); 154} 155 |
156static void 157clock_dbgprint_hdr(device_t dev, int rw) 158{ 159 struct timespec now; 160 161 getnanotime(&now); 162 device_printf(dev, "%s at ", (rw & CLOCK_DBG_READ) ? "read " : "write"); 163 clock_print_ts(&now, 9); 164 printf(": "); 165} 166 |
|
147void | 167void |
168clock_dbgprint_bcd(device_t dev, int rw, const struct bcd_clocktime *bct) 169{ 170 171 if (show_io & rw) { 172 clock_dbgprint_hdr(dev, rw); 173 clock_print_bcd(bct, 9); 174 printf("\n"); 175 } 176} 177 178void 179clock_dbgprint_ct(device_t dev, int rw, const struct clocktime *ct) 180{ 181 182 if (show_io & rw) { 183 clock_dbgprint_hdr(dev, rw); 184 clock_print_ct(ct, 9); 185 printf("\n"); 186 } 187} 188 189void 190clock_dbgprint_err(device_t dev, int rw, int err) 191{ 192 193 if (show_io & rw) { 194 clock_dbgprint_hdr(dev, rw); 195 printf("error = %d\n", err); 196 } 197} 198 199void 200clock_dbgprint_ts(device_t dev, int rw, const struct timespec *ts) 201{ 202 203 if (show_io & rw) { 204 clock_dbgprint_hdr(dev, rw); 205 clock_print_ts(ts, 9); 206 printf("\n"); 207 } 208} 209 210void |
|
148clock_register_flags(device_t clockdev, long resolution, int flags) 149{ 150 struct rtc_instance *rtc, *newrtc; 151 152 newrtc = malloc(sizeof(*newrtc), M_DEVBUF, M_WAITOK); 153 newrtc->clockdev = clockdev; 154 newrtc->resolution = (int)resolution; 155 newrtc->flags = flags; --- 42 unchanged lines hidden (view full) --- 198 LIST_REMOVE(rtc, rtc_entries); 199 break; 200 } 201 } 202 sx_xunlock(&rtc_list_lock); 203 if (rtc != NULL) { 204 taskqueue_cancel_timeout(taskqueue_thread, &rtc->stask, NULL); 205 taskqueue_drain_timeout(taskqueue_thread, &rtc->stask); | 211clock_register_flags(device_t clockdev, long resolution, int flags) 212{ 213 struct rtc_instance *rtc, *newrtc; 214 215 newrtc = malloc(sizeof(*newrtc), M_DEVBUF, M_WAITOK); 216 newrtc->clockdev = clockdev; 217 newrtc->resolution = (int)resolution; 218 newrtc->flags = flags; --- 42 unchanged lines hidden (view full) --- 261 LIST_REMOVE(rtc, rtc_entries); 262 break; 263 } 264 } 265 sx_xunlock(&rtc_list_lock); 266 if (rtc != NULL) { 267 taskqueue_cancel_timeout(taskqueue_thread, &rtc->stask, NULL); 268 taskqueue_drain_timeout(taskqueue_thread, &rtc->stask); |
206 free(rtc, M_DEVBUF); | 269 free(rtc, M_DEVBUF); |
207 } 208} 209 210void 211clock_schedule(device_t clockdev, u_int offsetns) 212{ 213 struct rtc_instance *rtc; 214 215 sx_xlock(&rtc_list_lock); 216 LIST_FOREACH(rtc, &rtc_list, rtc_entries) { 217 if (rtc->clockdev == clockdev) { 218 rtc->schedns = offsetns; 219 break; 220 } 221 } 222 sx_xunlock(&rtc_list_lock); 223} 224 | 270 } 271} 272 273void 274clock_schedule(device_t clockdev, u_int offsetns) 275{ 276 struct rtc_instance *rtc; 277 278 sx_xlock(&rtc_list_lock); 279 LIST_FOREACH(rtc, &rtc_list, rtc_entries) { 280 if (rtc->clockdev == clockdev) { 281 rtc->schedns = offsetns; 282 break; 283 } 284 } 285 sx_xunlock(&rtc_list_lock); 286} 287 |
288static int 289read_clocks(struct timespec *ts, bool debug_read) 290{ 291 struct rtc_instance *rtc; 292 int error; 293 294 error = ENXIO; 295 sx_xlock(&rtc_list_lock); 296 LIST_FOREACH(rtc, &rtc_list, rtc_entries) { 297 if ((error = CLOCK_GETTIME(rtc->clockdev, ts)) != 0) 298 continue; 299 if (ts->tv_sec < 0 || ts->tv_nsec < 0) { 300 error = EINVAL; 301 continue; 302 } 303 if (!(rtc->flags & CLOCKF_GETTIME_NO_ADJ)) { 304 timespecadd(ts, &rtc->resadj); 305 ts->tv_sec += utc_offset(); 306 } 307 if (!debug_read) { 308 if (bootverbose) 309 device_printf(rtc->clockdev, 310 "providing initial system time\n"); 311 break; 312 } 313 } 314 sx_xunlock(&rtc_list_lock); 315 return (error); 316} 317 |
|
225/* 226 * Initialize the system time. Must be called from a context which does not 227 * restrict any locking or sleeping that clock drivers may need to do. 228 * 229 * First attempt to get the time from a registered realtime clock. The clocks 230 * are queried in order of resolution until one provides the time. If no clock 231 * can provide the current time, use the 'base' time provided by the caller, if 232 * non-zero. The 'base' time is potentially highly inaccurate, such as the last 233 * known good value of the system clock, or even a filesystem last-updated 234 * timestamp. It is used to prevent system time from appearing to move 235 * backwards in logs. 236 */ 237void 238inittodr(time_t base) 239{ 240 struct timespec ts; | 318/* 319 * Initialize the system time. Must be called from a context which does not 320 * restrict any locking or sleeping that clock drivers may need to do. 321 * 322 * First attempt to get the time from a registered realtime clock. The clocks 323 * are queried in order of resolution until one provides the time. If no clock 324 * can provide the current time, use the 'base' time provided by the caller, if 325 * non-zero. The 'base' time is potentially highly inaccurate, such as the last 326 * known good value of the system clock, or even a filesystem last-updated 327 * timestamp. It is used to prevent system time from appearing to move 328 * backwards in logs. 329 */ 330void 331inittodr(time_t base) 332{ 333 struct timespec ts; |
241 struct rtc_instance *rtc; | |
242 int error; 243 | 334 int error; 335 |
244 error = ENXIO; 245 sx_xlock(&rtc_list_lock); 246 LIST_FOREACH(rtc, &rtc_list, rtc_entries) { 247 if ((error = CLOCK_GETTIME(rtc->clockdev, &ts)) != 0) 248 continue; 249 if (ts.tv_sec < 0 || ts.tv_nsec < 0) { 250 error = EINVAL; 251 continue; 252 } 253 if (!(rtc->flags & CLOCKF_GETTIME_NO_ADJ)) { 254 timespecadd(&ts, &rtc->resadj); 255 ts.tv_sec += utc_offset(); 256 } 257 if (bootverbose) 258 device_printf(rtc->clockdev, 259 "providing initial system time\n"); 260 break; 261 } 262 sx_xunlock(&rtc_list_lock); | 336 error = read_clocks(&ts, false); |
263 264 /* 265 * Do not report errors from each clock; it is expected that some clocks 266 * cannot provide results in some situations. Only report problems when 267 * no clocks could provide the time. 268 */ 269 if (error != 0) { 270 switch (error) { --- 46 unchanged lines hidden (view full) --- 317 sbt = nstosbt(waitns); 318 } else 319 sbt = 0; 320 taskqueue_enqueue_timeout_sbt(taskqueue_thread, 321 &rtc->stask, -sbt, 0, C_PREL(31)); 322 } 323 sx_xunlock(&rtc_list_lock); 324} | 337 338 /* 339 * Do not report errors from each clock; it is expected that some clocks 340 * cannot provide results in some situations. Only report problems when 341 * no clocks could provide the time. 342 */ 343 if (error != 0) { 344 switch (error) { --- 46 unchanged lines hidden (view full) --- 391 sbt = nstosbt(waitns); 392 } else 393 sbt = 0; 394 taskqueue_enqueue_timeout_sbt(taskqueue_thread, 395 &rtc->stask, -sbt, 0, C_PREL(31)); 396 } 397 sx_xunlock(&rtc_list_lock); 398} |
399 400static int 401sysctl_clock_do_io(SYSCTL_HANDLER_ARGS) 402{ 403 struct timespec ts_discard; 404 int error, value; 405 406 value = 0; 407 error = sysctl_handle_int(oidp, &value, 0, req); 408 if (error != 0 || req->newptr == NULL) 409 return (error); 410 411 switch (value) { 412 case CLOCK_DBG_READ: 413 if (read_clocks(&ts_discard, true) == ENXIO) 414 printf("No registered RTC clocks\n"); 415 break; 416 case CLOCK_DBG_WRITE: 417 resettodr(); 418 break; 419 default: 420 return (EINVAL); 421 } 422 423 return (0); 424} |
|