diff options
author | Alistair Popple <alistair@popple.id.au> | 2014-11-13 17:16:01 +1100 |
---|---|---|
committer | Stewart Smith <stewart@linux.vnet.ibm.com> | 2014-12-02 18:38:04 +1100 |
commit | eaf4cd02d38946a701f2174b9b8d44156e006eaf (patch) | |
tree | d3fa5ffc5ce7c4a18460801193064c568689530f | |
parent | 5819941efc10da9ddf9ce18f6249385eeebcaa6b (diff) | |
download | skiboot-eaf4cd02d38946a701f2174b9b8d44156e006eaf.zip skiboot-eaf4cd02d38946a701f2174b9b8d44156e006eaf.tar.gz skiboot-eaf4cd02d38946a701f2174b9b8d44156e006eaf.tar.bz2 |
rtc: Add a generic rtc cache
Some of the generic skiboot code needs access to the rtc (for example
the pel logging code). Currently this is accessed via a call to fsp
specific code which implements an rtc cache. Obviously this wont work
on systems without a fsp.
This patch makes the rtc cache generic so that we can get the time on
other platforms (assuming they have some kind of rtc).
Signed-off-by: Alistair Popple <alistair@popple.id.au>
Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
-rw-r--r-- | core/Makefile.inc | 2 | ||||
-rw-r--r-- | core/pel.c | 5 | ||||
-rw-r--r-- | core/rtc.c | 69 | ||||
-rw-r--r-- | hw/fsp/fsp-rtc.c | 72 | ||||
-rw-r--r-- | include/rtc.h | 40 |
5 files changed, 130 insertions, 58 deletions
diff --git a/core/Makefile.inc b/core/Makefile.inc index 615b27b..8540695 100644 --- a/core/Makefile.inc +++ b/core/Makefile.inc @@ -7,7 +7,7 @@ CORE_OBJS += timebase.o opal-msg.o pci.o pci-opal.o fast-reboot.o CORE_OBJS += device.o exceptions.o trace.o affinity.o vpd.o CORE_OBJS += hostservices.o platform.o nvram.o flash-nvram.o hmi.o CORE_OBJS += console-log.o ipmi.o time-utils.o pel.o pool.o errorlog.o -CORE_OBJS += timer.o i2c.o +CORE_OBJS += timer.o i2c.o rtc.o CORE=core/built-in.o CFLAGS_SKIP_core/relocate.o = -pg -fstack-protector-all @@ -3,6 +3,7 @@ #include <device.h> #include <fsp.h> #include <pel.h> +#include <rtc.h> /* Create MTMS section for sapphire log */ static void create_mtms_section(struct errorlog *elog_data, @@ -56,7 +57,7 @@ static void create_extended_header_section(struct errorlog *elog_data, memset(extdhdr->opal_subsys_version, 0x00, sizeof(extdhdr->opal_subsys_version)); - fsp_rtc_get_cached_tod(&extdhdr->extended_header_date, &extd_time); + rtc_cache_get_datetime(&extdhdr->extended_header_date, &extd_time); extdhdr->extended_header_time = extd_time >> 32; extdhdr->opal_symid_len = 0; @@ -159,7 +160,7 @@ static void create_private_header_section(struct errorlog *elog_data, privhdr->v6header.component_id = elog_data->component_id; privhdr->plid = elog_data->plid; - fsp_rtc_get_cached_tod(&privhdr->create_date, &ctime); + rtc_cache_get_datetime(&privhdr->create_date, &ctime); privhdr->create_time = ctime >> 32; privhdr->section_count = 5; diff --git a/core/rtc.c b/core/rtc.c new file mode 100644 index 0000000..60d2d85 --- /dev/null +++ b/core/rtc.c @@ -0,0 +1,69 @@ +/* Copyright 2013-2014 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include <skiboot.h> +#include <lock.h> +#include <rtc.h> +#include <timebase.h> + +static struct lock rtc_tod_lock = LOCK_UNLOCKED; + +static struct { + struct tm tm; + unsigned long tb; + bool valid; +} rtc_tod_cache; + +void rtc_cache_update(struct tm *tm) +{ + lock(&rtc_tod_lock); + rtc_tod_cache.tb = mftb(); + rtc_tod_cache.tm = *tm; + rtc_tod_cache.valid = true; + unlock(&rtc_tod_lock); +} + +int rtc_cache_get(struct tm *tm) +{ + unsigned long cache_age_sec; + + lock(&rtc_tod_lock); + if (!rtc_tod_cache.valid) + return -1; + + cache_age_sec = tb_to_msecs(mftb() - rtc_tod_cache.tb) / 1000; + *tm = rtc_tod_cache.tm; + unlock(&rtc_tod_lock); + + tm->tm_sec += cache_age_sec; + mktime(tm); + + return 0; +} + +int rtc_cache_get_datetime(uint32_t *year_month_day, + uint64_t *hour_minute_second_millisecond) +{ + struct tm tm; + + if (rtc_cache_get(&tm) < 0) + return -1; + + tm_to_datetime(&tm, year_month_day, hour_minute_second_millisecond); + + return 0; +} diff --git a/hw/fsp/fsp-rtc.c b/hw/fsp/fsp-rtc.c index bafcc33..eff2c84 100644 --- a/hw/fsp/fsp-rtc.c +++ b/hw/fsp/fsp-rtc.c @@ -52,12 +52,16 @@ * of the two has a pending event to signal. */ +#include <rtc.h> + enum { RTC_TOD_VALID, RTC_TOD_INVALID, RTC_TOD_PERMANENT_ERROR, } rtc_tod_state = RTC_TOD_INVALID; +bool rtc_tod_cache_dirty = false; + static struct lock rtc_lock; static struct fsp_msg *rtc_read_msg; static struct fsp_msg *rtc_write_msg; @@ -67,13 +71,6 @@ static struct fsp_msg *rtc_write_msg; */ static bool fsp_in_reset = false; -/* last synchonisation point */ -static struct { - struct tm tm; - unsigned long tb; - bool dirty; -} rtc_tod_cache; - struct opal_tpo_data { uint64_t tpo_async_token; uint32_t *year_month_day; @@ -95,16 +92,6 @@ DEFINE_LOG_ENTRY(OPAL_RC_RTC_READ, OPAL_PLATFORM_ERR_EVT, OPAL_RTC, OPAL_PLATFORM_FIRMWARE, OPAL_INFO, OPAL_NA, NULL); -static void tm_add(struct tm *in, struct tm *out, unsigned long secs) -{ - assert(in); - assert(out); - - *out = *in; - out->tm_sec += secs; - mktime(out); -} - static void fsp_tpo_req_complete(struct fsp_msg *read_resp) { struct opal_tpo_data *attr = read_resp->user_data; @@ -154,6 +141,7 @@ static void fsp_tpo_req_complete(struct fsp_msg *read_resp) static void fsp_rtc_process_read(struct fsp_msg *read_resp) { int val = (read_resp->word1 >> 8) & 0xff; + struct tm tm; switch (val) { case FSP_STATUS_TOD_RESET: @@ -171,9 +159,8 @@ static void fsp_rtc_process_read(struct fsp_msg *read_resp) case FSP_STATUS_SUCCESS: /* Save the read RTC value in our cache */ datetime_to_tm(read_resp->data.words[0], - (u64) read_resp->data.words[1] << 32, &rtc_tod_cache.tm); - rtc_tod_cache.tb = mftb(); - rtc_tod_state = RTC_TOD_VALID; + (u64) read_resp->data.words[1] << 32, &tm); + rtc_cache_update(&tm); break; default: @@ -230,32 +217,6 @@ static int64_t fsp_rtc_send_read_request(void) return OPAL_BUSY_EVENT; } -static void encode_cached_tod(uint32_t *year_month_day, - uint64_t *hour_minute_second_millisecond) -{ - unsigned long cache_age_sec; - struct tm tm; - - cache_age_sec = tb_to_msecs(mftb() - rtc_tod_cache.tb) / 1000; - - tm_add(&rtc_tod_cache.tm, &tm, cache_age_sec); - - /* Format to OPAL API values */ - tm_to_datetime(&tm, year_month_day, hour_minute_second_millisecond); -} - -int fsp_rtc_get_cached_tod(uint32_t *year_month_day, - uint64_t *hour_minute_second_millisecond) -{ - - if (rtc_tod_state != RTC_TOD_VALID) - return -1; - - encode_cached_tod(year_month_day, - hour_minute_second_millisecond); - return 0; -} - static int64_t fsp_opal_rtc_read(uint32_t *year_month_day, uint64_t *hour_minute_second_millisecond) { @@ -268,7 +229,7 @@ static int64_t fsp_opal_rtc_read(uint32_t *year_month_day, lock(&rtc_lock); /* During R/R of FSP, read cached TOD */ if (fsp_in_reset) { - fsp_rtc_get_cached_tod(year_month_day, + rtc_cache_get_datetime(year_month_day, hour_minute_second_millisecond); rc = OPAL_SUCCESS; goto out; @@ -299,7 +260,7 @@ static int64_t fsp_opal_rtc_read(uint32_t *year_month_day, fsp_freemsg(msg); if (rtc_tod_state == RTC_TOD_VALID) { - encode_cached_tod(year_month_day, + rtc_cache_get_datetime(year_month_day, hour_minute_second_millisecond); rc = OPAL_SUCCESS; } else @@ -310,7 +271,7 @@ static int64_t fsp_opal_rtc_read(uint32_t *year_month_day, } else if (mftb() > read_req_tb + msecs_to_tb(rtc_read_timeout_ms)) { prlog(PR_TRACE, "RTC read timed out\n"); - encode_cached_tod(year_month_day, + rtc_cache_get_datetime(year_month_day, hour_minute_second_millisecond); rc = OPAL_SUCCESS; @@ -329,6 +290,7 @@ static int64_t fsp_opal_rtc_write(uint32_t year_month_day, struct fsp_msg *msg; uint32_t w0, w1, w2; int64_t rc; + struct tm tm; lock(&rtc_lock); if (rtc_tod_state == RTC_TOD_PERMANENT_ERROR) { @@ -386,9 +348,9 @@ static int64_t fsp_opal_rtc_write(uint32_t year_month_day, if (fsp_in_reset) { datetime_to_tm(rtc_write_msg->data.words[0], - (u64) rtc_write_msg->data.words[1] << 32, &rtc_tod_cache.tm); - rtc_tod_cache.tb = mftb(); - rtc_tod_cache.dirty = true; + (u64) rtc_write_msg->data.words[1] << 32, &tm); + rtc_cache_update(&tm); + rtc_tod_cache_dirty = true; fsp_freemsg(rtc_write_msg); rtc_write_msg = NULL; rc = OPAL_SUCCESS; @@ -491,7 +453,7 @@ static void rtc_flush_cached_tod(void) uint64_t h_m_s_m; uint32_t y_m_d; - if (fsp_rtc_get_cached_tod(&y_m_d, &h_m_s_m)) + if (rtc_cache_get_datetime(&y_m_d, &h_m_s_m)) return; msg = fsp_mkmsg(FSP_CMD_WRITE_TOD, 3, y_m_d, (h_m_s_m >> 32) & 0xffffff00, 0); @@ -515,9 +477,9 @@ static bool fsp_rtc_msg_rr(u32 cmd_sub_mod, struct fsp_msg *msg) case FSP_RELOAD_COMPLETE: lock(&rtc_lock); fsp_in_reset = false; - if (rtc_tod_cache.dirty) { + if (rtc_tod_cache_dirty) { rtc_flush_cached_tod(); - rtc_tod_cache.dirty = false; + rtc_tod_cache_dirty = false; } unlock(&rtc_lock); rc = true; diff --git a/include/rtc.h b/include/rtc.h new file mode 100644 index 0000000..a993fd4 --- /dev/null +++ b/include/rtc.h @@ -0,0 +1,40 @@ +/* Copyright 2013-2014 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __RTC_H +#define __RTC_H + +#include <time-utils.h> + +/* + * Update the cache to the current time as specified by tm. + */ +void rtc_cache_update(struct tm *tm); + +/* + * Get the current time based on the cache. If the cache is valid the result + * is returned in tm and the function returns 0. Otherwise returns -1. + */ +int rtc_cache_get(struct tm *tm); + +/* + * Same as the previous function except the result is returned as an OPAL + * datetime. + */ +int rtc_cache_get_datetime(uint32_t *year_month_day, + uint64_t *hour_minute_second_millisecond); + +#endif |