03831d35f7499c87d51205817c93e9a8d42c4baestevel * CDDL HEADER START
03831d35f7499c87d51205817c93e9a8d42c4baestevel * The contents of this file are subject to the terms of the
88294e09b5c27cbb12b6735e2fb247a86b76666dRichard Bean * Common Development and Distribution License (the "License").
88294e09b5c27cbb12b6735e2fb247a86b76666dRichard Bean * You may not use this file except in compliance with the License.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
03831d35f7499c87d51205817c93e9a8d42c4baestevel * See the License for the specific language governing permissions
03831d35f7499c87d51205817c93e9a8d42c4baestevel * and limitations under the License.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * When distributing Covered Code, include this CDDL HEADER in each
03831d35f7499c87d51205817c93e9a8d42c4baestevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * If applicable, add the following below this CDDL HEADER, with the
03831d35f7499c87d51205817c93e9a8d42c4baestevel * fields enclosed by brackets "[]" replaced with your own identifying
03831d35f7499c87d51205817c93e9a8d42c4baestevel * information: Portions Copyright [yyyy] [name of copyright owner]
03831d35f7499c87d51205817c93e9a8d42c4baestevel * CDDL HEADER END
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Use is subject to license terms.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * tod driver module for Serengeti
03831d35f7499c87d51205817c93e9a8d42c4baestevel * This module implements a soft tod since
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Serengeti has no tod part.
03831d35f7499c87d51205817c93e9a8d42c4baestevel#endif /* DEBUG */
03831d35f7499c87d51205817c93e9a8d42c4baestevel#define OFFSET(base, field) ((char *)&base.field - (char *)&base)
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic void todsg_clear_power_alarm(void);
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int update_heartbeat(void);
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int verify_sc_tod_version(void);
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Module linkage information for the kernel.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * To obtain the initial start of day time, we use an
03831d35f7499c87d51205817c93e9a8d42c4baestevel * OBP callback; this is because the iosram is not yet
03831d35f7499c87d51205817c93e9a8d42c4baestevel * accessible from the OS at this early stage of startup.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Set the string to pass to OBP
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson "h# %p \" unix-get-tod\" $find if execute else 3drop then",
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson "This can be caused by older firmware.");
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson "Controller firmware to the latest version.\n");
03831d35f7499c87d51205817c93e9a8d42c4baestevel cmn_err(CE_CONT, "Attempting to set the date and time "
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson "based on the last shutdown.\n");
03831d35f7499c87d51205817c93e9a8d42c4baestevel cmn_err(CE_CONT, "Please inspect the date and time and "
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson "correct if necessary.\n");
03831d35f7499c87d51205817c93e9a8d42c4baestevel DCMNERR(CE_NOTE, "todsg: _init(): time from OBP 0x%lX",
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Verify whether the received date/clock has overflowed
03831d35f7499c87d51205817c93e9a8d42c4baestevel * an integer(32bit), so that we capture any corrupted
03831d35f7499c87d51205817c93e9a8d42c4baestevel * date from SC, thereby preventing boot failure.
03831d35f7499c87d51205817c93e9a8d42c4baestevel cmn_err(CE_CONT, "Attempting to set the date and time "
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson "based on the last shutdown.\n");
03831d35f7499c87d51205817c93e9a8d42c4baestevel cmn_err(CE_CONT, "Please inspect the date and time and "
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson "correct if necessary.\n");
03831d35f7499c87d51205817c93e9a8d42c4baestevel * By setting hrestime.tv_sec to zero
03831d35f7499c87d51205817c93e9a8d42c4baestevel * we force the vfs_mountroot() to set
03831d35f7499c87d51205817c93e9a8d42c4baestevel * the date from the last shutdown.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Save the skew so that we can update
03831d35f7499c87d51205817c93e9a8d42c4baestevel * IOSRAM when it becomes accessible.
03831d35f7499c87d51205817c93e9a8d42c4baestevel tod_ops.tod_set_watchdog_timer = todsg_set_watchdog_timer;
03831d35f7499c87d51205817c93e9a8d42c4baestevel tod_ops.tod_clear_watchdog_timer = todsg_clear_watchdog_timer;
03831d35f7499c87d51205817c93e9a8d42c4baestevel tod_ops.tod_clear_power_alarm = todsg_clear_power_alarm;
03831d35f7499c87d51205817c93e9a8d42c4baestevel tod_ops.tod_get_cpufrequency = todsg_get_cpufrequency;
03831d35f7499c87d51205817c93e9a8d42c4baestevel /* Update the heartbeat */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (iosram_write(SBBC_TOD_KEY, OFFSET(tod_buf, tod_i_am_alive),
03831d35f7499c87d51205817c93e9a8d42c4baestevel cmn_err(CE_WARN, "update_heartbeat(): write heartbeat failed");
03831d35f7499c87d51205817c93e9a8d42c4baestevel * read tod_version only when the first time and
03831d35f7499c87d51205817c93e9a8d42c4baestevel * when there has been a previous sc down time
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (!sc_tod_version || is_sc_down >= SC_DOWN_COUNT_THRESHOLD) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (iosram_read(SBBC_TOD_KEY, OFFSET(tod_buf, tod_magic),
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson "TOD SRAM magic error");
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (iosram_read(SBBC_TOD_KEY, OFFSET(tod_buf, tod_version),
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson (char *)&sc_tod_version, sizeof (uint32_t))) {
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson "read tod version failed");
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson cmn_err(CE_WARN, "todsg_get(): incorrect firmware version, "
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson "(%d): expected version >= %d.", sc_tod_version,
03831d35f7499c87d51205817c93e9a8d42c4baestevel DCMNERR(CE_NOTE, "update_tod_skew(): skew 0x%lX", skew);
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (iosram_read(SBBC_TOD_KEY, OFFSET(tod_buf, tod_domain_skew),
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson "update_tod_skew(): read tod domain skew failed");
03831d35f7499c87d51205817c93e9a8d42c4baestevel /* we shall update the skew_adjust too now */
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson OFFSET(tod_buf, tod_domain_skew), (char *)&domain_skew,
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson "update_tod_skew(): write domain skew failed");
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Return time value read from IOSRAM.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Must be called with tod_lock held.
03831d35f7499c87d51205817c93e9a8d42c4baestevel /* if we can't use SC */
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson OFFSET(tod_buf, tod_get_value), (char *)&seconds,
03831d35f7499c87d51205817c93e9a8d42c4baestevel cmn_err(CE_WARN, "todsg_get(): read 64-bit tod value failed");
03831d35f7499c87d51205817c93e9a8d42c4baestevel * This is our first chance to update IOSRAM
03831d35f7499c87d51205817c93e9a8d42c4baestevel * with local copy of the skew, so update it.
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson OFFSET(tod_buf, tod_domain_skew), (char *)&domain_skew,
03831d35f7499c87d51205817c93e9a8d42c4baestevel cmn_err(CE_WARN, "todsg_get(): read tod domain skew failed");
03831d35f7499c87d51205817c93e9a8d42c4baestevel cmn_err(CE_WARN, "todsg_get(): turned off using tod");
03831d35f7499c87d51205817c93e9a8d42c4baestevel * If the SC gets rebooted, and we are using NTP, then we need
03831d35f7499c87d51205817c93e9a8d42c4baestevel * to sync the IOSRAM to hrestime when the SC comes back. We
03831d35f7499c87d51205817c93e9a8d42c4baestevel * can determine that either NTP slew (or date -a) was called if
03831d35f7499c87d51205817c93e9a8d42c4baestevel * the global timedelta was non-zero at any point while the SC
03831d35f7499c87d51205817c93e9a8d42c4baestevel * was away. If timedelta remains zero throughout, then the
03831d35f7499c87d51205817c93e9a8d42c4baestevel * default action will be to sync hrestime to IOSRAM
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (is_sc_down >= SC_DOWN_COUNT_THRESHOLD && adjust_sc_down) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel skew_adjust = hrestime.tv_sec - (seconds + domain_skew);
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson "read tod domain skew failed");
03831d35f7499c87d51205817c93e9a8d42c4baestevel * If complained then domain_skew is invalid.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Hand back hrestime instead.
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson * The read was successful so ensure the failure
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson * flag is clear.
03831d35f7499c87d51205817c93e9a8d42c4baestevel /* SC/TOD is down */
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson * We need to inform the tod_validate() code to stop checking until
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson * the SC comes back up again. Note we will return hrestime below
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson * which may be different to the previous TOD value we returned.
03831d35f7499c87d51205817c93e9a8d42c4baestevel /* if we can't use SC */
03831d35f7499c87d51205817c93e9a8d42c4baestevel * If the SC is down just note the fact that we should
03831d35f7499c87d51205817c93e9a8d42c4baestevel * have adjusted the hardware skew which caters for calls
03831d35f7499c87d51205817c93e9a8d42c4baestevel * to stime(). (eg NTP step, as opposed to NTP skew)
03831d35f7499c87d51205817c93e9a8d42c4baestevel * reason to update i_am_alive here:
03831d35f7499c87d51205817c93e9a8d42c4baestevel * To work around a generic Solaris bug that can
03831d35f7499c87d51205817c93e9a8d42c4baestevel * cause tod_get() to be starved by too frequent
03831d35f7499c87d51205817c93e9a8d42c4baestevel * calls to the stime() system call.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * We are passed hrestime from clock.c so we need to read the
03831d35f7499c87d51205817c93e9a8d42c4baestevel * IOSRAM for the hardware's idea of the time to see if we need
03831d35f7499c87d51205817c93e9a8d42c4baestevel * to update the skew.
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson OFFSET(tod_buf, tod_get_value), (char *)&seconds,
03831d35f7499c87d51205817c93e9a8d42c4baestevel cmn_err(CE_WARN, "todsg_set(): read 64-bit tod value failed");
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson OFFSET(tod_buf, tod_domain_skew), (char *)&domain_skew,
03831d35f7499c87d51205817c93e9a8d42c4baestevel cmn_err(CE_WARN, "todsg_set(): read tod domain skew failed");
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Only update the skew if the time passed differs from
03831d35f7499c87d51205817c93e9a8d42c4baestevel * what the hardware thinks & no errors talking to SC
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (!complained && (ts.tv_sec != (seconds + domain_skew))) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel DCMNERR(CE_NOTE, "todsg_set(): set time %lX (%lX)%s",
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson ts.tv_sec, hwtod, complained ? " failed" : "");
03831d35f7499c87d51205817c93e9a8d42c4baestevel cmn_err(CE_WARN, "todsg_set(): turned off using tod");
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson "verify_sc_tod_version failed");
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (0);
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson "set watchdog timer value = %d", timeoutval);
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (iosram_write(SBBC_TOD_KEY, OFFSET(tod_buf, tod_timeout_period),
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson "write new timeout value failed");
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (0);
03831d35f7499c87d51205817c93e9a8d42c4baestevel if ((watchdog_activated == 0) || !verify_sc_tod_version()) {
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson "either watchdog not activated or "
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson "verify_sc_tod_version failed");
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (0);
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (iosram_read(SBBC_TOD_KEY, OFFSET(tod_buf, tod_timeout_period),
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson (char *)&r_timeout_period, sizeof (uint32_t))) {
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson "read timeout value failed");
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (0);
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson "clear watchdog timer (old value=%d)", r_timeout_period);
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (iosram_write(SBBC_TOD_KEY, OFFSET(tod_buf, tod_timeout_period),
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson (char *)&w_timeout_period, sizeof (uint32_t))) {
8fc99e42676a23421c75e76660640f9765d693b1Trevor Thompson "write zero timeout value failed");
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (0);
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Null function.
03831d35f7499c87d51205817c93e9a8d42c4baestevel/* ARGSUSED */
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Null function
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Get clock freq from the cpunode
03831d35f7499c87d51205817c93e9a8d42c4baestevel DCMNERR(CE_NOTE, "todsg_get_cpufrequency(): frequency=%ldMHz",