125cf1a30Sjl139090 /*
225cf1a30Sjl139090 * CDDL HEADER START
325cf1a30Sjl139090 *
425cf1a30Sjl139090 * The contents of this file are subject to the terms of the
525cf1a30Sjl139090 * Common Development and Distribution License (the "License").
625cf1a30Sjl139090 * You may not use this file except in compliance with the License.
725cf1a30Sjl139090 *
825cf1a30Sjl139090 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
925cf1a30Sjl139090 * or http://www.opensolaris.org/os/licensing.
1025cf1a30Sjl139090 * See the License for the specific language governing permissions
1125cf1a30Sjl139090 * and limitations under the License.
1225cf1a30Sjl139090 *
1325cf1a30Sjl139090 * When distributing Covered Code, include this CDDL HEADER in each
1425cf1a30Sjl139090 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1525cf1a30Sjl139090 * If applicable, add the following below this CDDL HEADER, with the
1625cf1a30Sjl139090 * fields enclosed by brackets "[]" replaced with your own identifying
1725cf1a30Sjl139090 * information: Portions Copyright [yyyy] [name of copyright owner]
1825cf1a30Sjl139090 *
1925cf1a30Sjl139090 * CDDL HEADER END
2025cf1a30Sjl139090 */
2125cf1a30Sjl139090 /*
2225cf1a30Sjl139090 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
2325cf1a30Sjl139090 * Use is subject to license terms.
2425cf1a30Sjl139090 */
2525cf1a30Sjl139090
2625cf1a30Sjl139090 /*
2725cf1a30Sjl139090 * tod driver module for OPL (implements a soft tod)
2825cf1a30Sjl139090 */
2925cf1a30Sjl139090
3025cf1a30Sjl139090 #include <sys/types.h>
3125cf1a30Sjl139090 #include <sys/param.h>
3225cf1a30Sjl139090 #include <sys/sysmacros.h>
3325cf1a30Sjl139090 #include <sys/systm.h>
3425cf1a30Sjl139090 #include <sys/errno.h>
3525cf1a30Sjl139090 #include <sys/modctl.h>
3625cf1a30Sjl139090 #include <sys/autoconf.h>
3725cf1a30Sjl139090 #include <sys/debug.h>
3825cf1a30Sjl139090 #include <sys/clock.h>
3925cf1a30Sjl139090 #include <sys/cmn_err.h>
4025cf1a30Sjl139090 #include <sys/prom_plat.h>
4125cf1a30Sjl139090 #include <sys/cpuvar.h>
4225cf1a30Sjl139090 #include <sys/opl_module.h>
4325cf1a30Sjl139090
4425cf1a30Sjl139090 /*
4525cf1a30Sjl139090 * Debug stuff
4625cf1a30Sjl139090 */
4725cf1a30Sjl139090 #ifdef DEBUG
4825cf1a30Sjl139090 int todopl_debug = 0;
4925cf1a30Sjl139090 #define TODOPL_DEBUG(args) if (todopl_debug) cmn_err args
5025cf1a30Sjl139090 #else
5125cf1a30Sjl139090 #define TODOPL_DEBUG(args)
5225cf1a30Sjl139090 #endif
5325cf1a30Sjl139090
5425cf1a30Sjl139090 #define abs(x) ((x) < 0 ? -(x) : (x))
5525cf1a30Sjl139090
5625cf1a30Sjl139090 #define TODOPL_SET_THRESHOLD 30
5725cf1a30Sjl139090
5825cf1a30Sjl139090 static timestruc_t todopl_get(void);
5925cf1a30Sjl139090 static void todopl_set(timestruc_t);
6025cf1a30Sjl139090 static uint_t todopl_set_watchdog_timer(uint_t);
6125cf1a30Sjl139090 static uint_t todopl_clear_watchdog_timer(void);
6225cf1a30Sjl139090 static void todopl_set_power_alarm(timestruc_t);
6325cf1a30Sjl139090 static void todopl_clear_power_alarm(void);
6425cf1a30Sjl139090 static uint64_t todopl_get_cpufrequency(void);
6525cf1a30Sjl139090
6625cf1a30Sjl139090 /*
6725cf1a30Sjl139090 * Module linkage information for the kernel.
6825cf1a30Sjl139090 */
6925cf1a30Sjl139090 static struct modlmisc modlmisc = {
7025cf1a30Sjl139090 &mod_miscops, "Soft tod module for OPL 1.11"
7125cf1a30Sjl139090 };
7225cf1a30Sjl139090
7325cf1a30Sjl139090 static struct modlinkage modlinkage = {
7425cf1a30Sjl139090 MODREV_1, (void *)&modlmisc, NULL
7525cf1a30Sjl139090 };
7625cf1a30Sjl139090
7725cf1a30Sjl139090 /*
7825cf1a30Sjl139090 * The TOD OPL logic description.
7925cf1a30Sjl139090 *
8025cf1a30Sjl139090 * The todopl driver uses promif functions prom_opl_get_tod() and
8125cf1a30Sjl139090 * prom_opl_set_diff(). These functions call FJSV,get-tod and
8225cf1a30Sjl139090 * FJSV,set-domain-time OBP client services.
8325cf1a30Sjl139090 *
8425cf1a30Sjl139090 * At the system boot or reboot:
8525cf1a30Sjl139090 *
8625cf1a30Sjl139090 * FJSV,tod-get
8725cf1a30Sjl139090 * OS ---------> OBP SCF I/F
8825cf1a30Sjl139090 * -----------> XSCF
8925cf1a30Sjl139090 * <-----------
9025cf1a30Sjl139090 * <-------- time, diff
9125cf1a30Sjl139090 * time+diff, stick
9225cf1a30Sjl139090 *
9325cf1a30Sjl139090 * Note that on first powerup domain boot, diff is zero.
9425cf1a30Sjl139090 *
95*bbf21555SRichard Lowe * When system updates the time via date(1):
9625cf1a30Sjl139090 *
9725cf1a30Sjl139090 * FJSV,set-domain-time
9825cf1a30Sjl139090 * OS ---------> OBP SRAM
9925cf1a30Sjl139090 * diff_delta diff += diff_delta -------------> XSCF
10025cf1a30Sjl139090 *
10125cf1a30Sjl139090 * diff_delta = new time - current domain time (hrestime)
10225cf1a30Sjl139090 *
10325cf1a30Sjl139090 *
10425cf1a30Sjl139090 * In theory, FJSV,get-tod and FJSV,set-domain-time should never fails.
10525cf1a30Sjl139090 * But, if call to FJSV,get-tod fails on boot, the domain will be unable
10625cf1a30Sjl139090 * to calculate "diff" properly and synchronization between Domain and
10725cf1a30Sjl139090 * SP will be broken. In this particular case, we notify users that
10825cf1a30Sjl139090 * "there is no time synchronization" and the logic will attempt to
10925cf1a30Sjl139090 * resync with the SP whenever the OS tries to do a TOD update.
110*bbf21555SRichard Lowe * (e.g. via date(1) or NTP).
11125cf1a30Sjl139090 */
11225cf1a30Sjl139090
11325cf1a30Sjl139090 static int enable_time_sync = 1;
11425cf1a30Sjl139090
11525cf1a30Sjl139090 int
_init(void)11625cf1a30Sjl139090 _init(void)
11725cf1a30Sjl139090 {
11825cf1a30Sjl139090 int64_t stick;
11925cf1a30Sjl139090 time_t obp_time = 0;
12025cf1a30Sjl139090 int64_t obp_stick;
12125cf1a30Sjl139090
12225cf1a30Sjl139090 if (strcmp(tod_module_name, "todopl") == 0) {
12325cf1a30Sjl139090 /*
12425cf1a30Sjl139090 * Get TOD time from OBP and adjust it.
12525cf1a30Sjl139090 */
12625cf1a30Sjl139090 prom_opl_get_tod(&obp_time, &obp_stick);
12725cf1a30Sjl139090
12825cf1a30Sjl139090 TODOPL_DEBUG((CE_NOTE, "todopl: OBP time 0x%lx stick 0x%lx\n",
12925cf1a30Sjl139090 obp_time, obp_stick));
13025cf1a30Sjl139090
13125cf1a30Sjl139090 if (obp_time != 0) {
13225cf1a30Sjl139090 /*
13325cf1a30Sjl139090 * adjust OBP time by stick counts
13425cf1a30Sjl139090 */
13525cf1a30Sjl139090 stick_timestamp(&stick);
13625cf1a30Sjl139090 obp_time += ((stick - obp_stick) / system_clock_freq);
13725cf1a30Sjl139090
13825cf1a30Sjl139090 TODOPL_DEBUG((CE_NOTE,
13925cf1a30Sjl139090 "todopl: cpu stick 0x%lx sys_time 0x%lx\n",
14025cf1a30Sjl139090 stick, obp_time));
14125cf1a30Sjl139090 } else {
14225cf1a30Sjl139090 /*
14325cf1a30Sjl139090 * A date of zero causes the root filesystem driver
14425cf1a30Sjl139090 * to try to set the date from the last shutdown.
14525cf1a30Sjl139090 */
14625cf1a30Sjl139090 enable_time_sync = 0;
14725cf1a30Sjl139090 cmn_err(CE_WARN, "Initial date is invalid.");
14825cf1a30Sjl139090 cmn_err(CE_CONT, "Attempting to set the date and time "
14925cf1a30Sjl139090 "based on the last shutdown.\n");
15025cf1a30Sjl139090 cmn_err(CE_CONT, "The time could not be synchronized "
15125cf1a30Sjl139090 "between Domain and Service Processor.\n");
15225cf1a30Sjl139090 cmn_err(CE_CONT, "Please inspect the date and time and "
15325cf1a30Sjl139090 "correct if necessary.\n");
15425cf1a30Sjl139090 }
15525cf1a30Sjl139090
15625cf1a30Sjl139090 hrestime.tv_sec = obp_time;
15725cf1a30Sjl139090
15825cf1a30Sjl139090 /*
15925cf1a30Sjl139090 * Check that the date has not overflowed a 32-bit integer.
16025cf1a30Sjl139090 */
16125cf1a30Sjl139090 if (TIMESPEC_OVERFLOW(&hrestime)) {
16225cf1a30Sjl139090 cmn_err(CE_WARN, "Date overflow detected.");
16325cf1a30Sjl139090 cmn_err(CE_CONT, "Attempting to set the date and time "
16425cf1a30Sjl139090 "based on the last shutdown.\n");
16525cf1a30Sjl139090 cmn_err(CE_CONT, "Please inspect the date and time and "
16625cf1a30Sjl139090 "correct if necessary.\n");
16725cf1a30Sjl139090
16825cf1a30Sjl139090 hrestime.tv_sec = (time_t)0;
16925cf1a30Sjl139090 }
17025cf1a30Sjl139090
17125cf1a30Sjl139090 tod_ops.tod_get = todopl_get;
17225cf1a30Sjl139090 tod_ops.tod_set = todopl_set;
17325cf1a30Sjl139090 tod_ops.tod_set_watchdog_timer = todopl_set_watchdog_timer;
17425cf1a30Sjl139090 tod_ops.tod_clear_watchdog_timer = todopl_clear_watchdog_timer;
17525cf1a30Sjl139090 tod_ops.tod_set_power_alarm = todopl_set_power_alarm;
17625cf1a30Sjl139090 tod_ops.tod_clear_power_alarm = todopl_clear_power_alarm;
17725cf1a30Sjl139090 tod_ops.tod_get_cpufrequency = todopl_get_cpufrequency;
17825cf1a30Sjl139090
17925cf1a30Sjl139090 /*
18025cf1a30Sjl139090 * Flag warning if user tried to use hardware watchdog
18125cf1a30Sjl139090 */
18225cf1a30Sjl139090 if (watchdog_enable) {
18325cf1a30Sjl139090 cmn_err(CE_WARN, "Hardware watchdog unavailable");
18425cf1a30Sjl139090 }
18525cf1a30Sjl139090 }
18625cf1a30Sjl139090
18725cf1a30Sjl139090 return (mod_install(&modlinkage));
18825cf1a30Sjl139090 }
18925cf1a30Sjl139090
19025cf1a30Sjl139090 int
_fini(void)19125cf1a30Sjl139090 _fini(void)
19225cf1a30Sjl139090 {
19325cf1a30Sjl139090 if (strcmp(tod_module_name, "todopl") == 0)
19425cf1a30Sjl139090 return (EBUSY);
19525cf1a30Sjl139090 else
19625cf1a30Sjl139090 return (mod_remove(&modlinkage));
19725cf1a30Sjl139090 }
19825cf1a30Sjl139090
19925cf1a30Sjl139090 int
_info(struct modinfo * modinfop)20025cf1a30Sjl139090 _info(struct modinfo *modinfop)
20125cf1a30Sjl139090 {
20225cf1a30Sjl139090 return (mod_info(&modlinkage, modinfop));
20325cf1a30Sjl139090 }
20425cf1a30Sjl139090
20525cf1a30Sjl139090
20625cf1a30Sjl139090 /*
20725cf1a30Sjl139090 * OPL tod_get is simplified to return hrestime
20825cf1a30Sjl139090 * Must be called with tod_lock held.
20925cf1a30Sjl139090 */
21025cf1a30Sjl139090 static timestruc_t
todopl_get(void)21125cf1a30Sjl139090 todopl_get(void)
21225cf1a30Sjl139090 {
21325cf1a30Sjl139090 ASSERT(MUTEX_HELD(&tod_lock));
21425cf1a30Sjl139090 return (hrestime);
21525cf1a30Sjl139090 }
21625cf1a30Sjl139090
21725cf1a30Sjl139090 /*
21825cf1a30Sjl139090 * Must be called with tod_lock held.
21925cf1a30Sjl139090 *
22025cf1a30Sjl139090 * When running NTP, tod_set is called at least once per second in order
22125cf1a30Sjl139090 * to update the hardware clock. To minimize pressure on SP, we want only
222*bbf21555SRichard Lowe * to record significant time changes on the SP (when date(1) is run).
22325cf1a30Sjl139090 * We have 30 seconds threshold requirement before recording the time change.
22425cf1a30Sjl139090 */
22525cf1a30Sjl139090 /* ARGSUSED */
22625cf1a30Sjl139090 static void
todopl_set(timestruc_t ts)22725cf1a30Sjl139090 todopl_set(timestruc_t ts)
22825cf1a30Sjl139090 {
22925cf1a30Sjl139090 ASSERT(MUTEX_HELD(&tod_lock));
23025cf1a30Sjl139090
23125cf1a30Sjl139090 if (abs(ts.tv_sec - hrestime.tv_sec) > TODOPL_SET_THRESHOLD) {
23225cf1a30Sjl139090 /*
23325cf1a30Sjl139090 * Send time difference to SP
23425cf1a30Sjl139090 */
23525cf1a30Sjl139090 if (enable_time_sync)
23625cf1a30Sjl139090 prom_opl_set_diff(ts.tv_sec - hrestime.tv_sec);
23725cf1a30Sjl139090 else {
23825cf1a30Sjl139090 /*
23925cf1a30Sjl139090 * We did not get a successful initial time
24025cf1a30Sjl139090 * update/sync from the SP via OBP during boot.
24125cf1a30Sjl139090 * Try again here.
24225cf1a30Sjl139090 */
24325cf1a30Sjl139090 time_t obp_time = 0;
24425cf1a30Sjl139090 int64_t obp_stick;
24525cf1a30Sjl139090 int64_t stick;
24625cf1a30Sjl139090
24725cf1a30Sjl139090 prom_opl_get_tod(&obp_time, &obp_stick);
24825cf1a30Sjl139090
24925cf1a30Sjl139090 if (obp_time != 0) {
25025cf1a30Sjl139090 /*
25125cf1a30Sjl139090 * adjust OBP time by stick counts
25225cf1a30Sjl139090 */
25325cf1a30Sjl139090 stick_timestamp(&stick);
25425cf1a30Sjl139090 obp_time += ((stick - obp_stick) /
25525cf1a30Sjl139090 system_clock_freq);
25625cf1a30Sjl139090
25725cf1a30Sjl139090 /*
25825cf1a30Sjl139090 * Sync up by computing the diff using the
25925cf1a30Sjl139090 * newly acquired SP/OBP reference time
26025cf1a30Sjl139090 */
26125cf1a30Sjl139090 prom_opl_set_diff(ts.tv_sec - obp_time);
26225cf1a30Sjl139090
26325cf1a30Sjl139090 enable_time_sync = 1;
26425cf1a30Sjl139090 }
26525cf1a30Sjl139090 }
26625cf1a30Sjl139090 TODOPL_DEBUG((CE_NOTE, "todopl_set: new domain time 0x%lx\n",
26725cf1a30Sjl139090 ts.tv_sec));
26825cf1a30Sjl139090 }
26925cf1a30Sjl139090 }
27025cf1a30Sjl139090
27125cf1a30Sjl139090 /*
27225cf1a30Sjl139090 * No watchdog function.
27325cf1a30Sjl139090 */
27425cf1a30Sjl139090 /* ARGSUSED */
27525cf1a30Sjl139090 static uint_t
todopl_set_watchdog_timer(uint_t timeoutval)27625cf1a30Sjl139090 todopl_set_watchdog_timer(uint_t timeoutval)
27725cf1a30Sjl139090 {
27825cf1a30Sjl139090 ASSERT(MUTEX_HELD(&tod_lock));
27925cf1a30Sjl139090 return (0);
28025cf1a30Sjl139090 }
28125cf1a30Sjl139090
28225cf1a30Sjl139090 /*
28325cf1a30Sjl139090 * No watchdog function
28425cf1a30Sjl139090 */
28525cf1a30Sjl139090 static uint_t
todopl_clear_watchdog_timer(void)28625cf1a30Sjl139090 todopl_clear_watchdog_timer(void)
28725cf1a30Sjl139090 {
28825cf1a30Sjl139090 ASSERT(MUTEX_HELD(&tod_lock));
28925cf1a30Sjl139090 return (0);
29025cf1a30Sjl139090 }
29125cf1a30Sjl139090
29225cf1a30Sjl139090 /*
29325cf1a30Sjl139090 * Null function.
29425cf1a30Sjl139090 */
29525cf1a30Sjl139090 /* ARGSUSED */
29625cf1a30Sjl139090 static void
todopl_set_power_alarm(timestruc_t ts)29725cf1a30Sjl139090 todopl_set_power_alarm(timestruc_t ts)
29825cf1a30Sjl139090 {
29925cf1a30Sjl139090 ASSERT(MUTEX_HELD(&tod_lock));
30025cf1a30Sjl139090 }
30125cf1a30Sjl139090
30225cf1a30Sjl139090 /*
30325cf1a30Sjl139090 * Null function
30425cf1a30Sjl139090 */
30525cf1a30Sjl139090 static void
todopl_clear_power_alarm()30625cf1a30Sjl139090 todopl_clear_power_alarm()
30725cf1a30Sjl139090 {
30825cf1a30Sjl139090 ASSERT(MUTEX_HELD(&tod_lock));
30925cf1a30Sjl139090 }
31025cf1a30Sjl139090
31125cf1a30Sjl139090 /*
31225cf1a30Sjl139090 * Get clock freq from the cpunode. This function is only called
31325cf1a30Sjl139090 * when use_stick = 0, otherwise, system_clock_freq gets used instead.
31425cf1a30Sjl139090 */
31525cf1a30Sjl139090 uint64_t
todopl_get_cpufrequency(void)31625cf1a30Sjl139090 todopl_get_cpufrequency(void)
31725cf1a30Sjl139090 {
31825cf1a30Sjl139090 return (cpunodes[CPU->cpu_id].clock_freq);
31925cf1a30Sjl139090 }
320