aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlistair Popple <alistair@popple.id.au>2014-08-15 14:31:22 +1000
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-08-15 14:36:38 +1000
commitaa3a45f47b0e85f453a5c2d1414bba668328737e (patch)
treebac0e10afcbc43c58fedd44ca1af77a953d65971
parent0890debca7cdd9a78ca2d6d52e07609404412818 (diff)
downloadskiboot-aa3a45f47b0e85f453a5c2d1414bba668328737e.zip
skiboot-aa3a45f47b0e85f453a5c2d1414bba668328737e.tar.gz
skiboot-aa3a45f47b0e85f453a5c2d1414bba668328737e.tar.bz2
fsp/rtc: Use libc time functions
Our libc now has a proper implementation of mktime, which makes adding tm structures together easy. This patch makes the FSP RTC functions use the library functions and removes the generic time calculation code from the FSP RTC driver. The OPAL<->tm conversion functions are also made public as they will be useful for the IPMI RTC implementation. Signed-off-by: Alistair Popple <alistair@popple.id.au> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r--core/Makefile.inc3
-rw-r--r--core/time-utils.c94
-rw-r--r--hw/fsp/fsp-rtc.c156
-rw-r--r--include/time-utils.h26
4 files changed, 130 insertions, 149 deletions
diff --git a/core/Makefile.inc b/core/Makefile.inc
index 274318d..714da3a 100644
--- a/core/Makefile.inc
+++ b/core/Makefile.inc
@@ -6,8 +6,7 @@ CORE_OBJS += malloc.o lock.o cpu.o utils.o fdt.o opal.o interrupts.o
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
+CORE_OBJS += console-log.o ipmi.o time-utils.o
CORE=core/built-in.o
$(CORE): $(CORE_OBJS:%=core/%)
-
diff --git a/core/time-utils.c b/core/time-utils.c
new file mode 100644
index 0000000..10a4da4
--- /dev/null
+++ b/core/time-utils.c
@@ -0,0 +1,94 @@
+/* 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 <time-utils.h>
+
+/* MSB is byte 3, LSB is byte 0 */
+static unsigned int bcd_byte(uint32_t bcd, int byteno)
+{
+ bcd >>= byteno * 8;
+ return (bcd >> 4 & 0xf) * 10 + (bcd & 0xf);
+}
+
+static uint32_t int_to_bcd2(unsigned int x)
+{
+ return (((x / 10) << 4) & 0xf0) | (x % 10);
+}
+
+static uint32_t int_to_bcd4(unsigned int x)
+{
+ return int_to_bcd2(x / 100) << 8 | int_to_bcd2(x % 100);
+}
+
+/*
+ * Converts an OPAL formated datetime into a struct tm. We ignore microseconds
+ * as Linux doesn't use them anyway.
+ *
+ * | year | month | mday |
+ * +------------------------------------+
+ * | hour | minute | secs | reserved |
+ * +------------------------------------+
+ * | microseconds |
+ */
+
+void datetime_to_tm(uint32_t y_m_d, uint64_t h_m_s_m, struct tm *tm)
+{
+ uint32_t x;
+
+ tm->tm_year = bcd_byte(y_m_d, 3) * 100 + bcd_byte(y_m_d, 2);
+ tm->tm_mon = bcd_byte(y_m_d, 1) - 1;
+ tm->tm_mday = bcd_byte(y_m_d, 0);
+
+ x = h_m_s_m >> 32;
+ tm->tm_hour = bcd_byte(x, 3);
+ tm->tm_min = bcd_byte(x, 2);
+ tm->tm_sec = bcd_byte(x, 1);
+}
+
+/*
+ * The OPAL API is defined as returned a u64 of a similar
+ * format to the FSP message; the 32-bit date field is
+ * in the format:
+ *
+ * | year | month | mday |
+ *
+ * ... and the 64-bit time field is in the format
+ *
+ * | hour | minutes | secs | millisec |
+ * | -------------------------------------
+ * | millisec | reserved |
+ *
+ * We simply ignore the microseconds/milliseconds for now
+ * as I don't quite understand why the OPAL API defines that
+ * it needs 6 digits for the milliseconds :-) I suspect the
+ * doc got that wrong and it's supposed to be micro but
+ * let's ignore it.
+ *
+ * Note that Linux doesn't use nor set the ms field anyway.
+ */
+void tm_to_datetime(struct tm *tm, uint32_t *y_m_d, uint64_t *h_m_s_m)
+{
+ uint64_t h_m_s;
+ *y_m_d = int_to_bcd4(tm->tm_year) << 16 |
+ int_to_bcd2(tm->tm_mon + 1) << 8 |
+ int_to_bcd2(tm->tm_mday);
+
+ h_m_s = int_to_bcd2(tm->tm_hour) << 24 |
+ int_to_bcd2(tm->tm_min) << 16 |
+ int_to_bcd2(tm->tm_sec) << 8;
+
+ *h_m_s_m = h_m_s << 32;
+}
diff --git a/hw/fsp/fsp-rtc.c b/hw/fsp/fsp-rtc.c
index 2ec88ca..69b2c73 100644
--- a/hw/fsp/fsp-rtc.c
+++ b/hw/fsp/fsp-rtc.c
@@ -19,6 +19,7 @@
#include <lock.h>
#include <timebase.h>
#include <time.h>
+#include <time-utils.h>
#include <opal-msg.h>
#include <fsp-elog.h>
#include <device.h>
@@ -97,155 +98,14 @@ DEFINE_LOG_ENTRY(OPAL_RC_RTC_READ, OPAL_PLATFORM_ERR_EVT, OPAL_RTC,
OPAL_PLATFORM_FIRMWARE, OPAL_INFO,
OPAL_NA, NULL);
-static int days_in_month(int month, int year)
-{
- static int month_days[] = {
- 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
- };
-
- assert(1 <= month && month <= 12);
-
- /* we may need to update this in the year 4000, pending a
- * decision on whether or not it's a leap year */
- if (month == 2) {
- bool is_leap = !(year % 400) || ((year % 100) && !(year % 4));
- return is_leap ? 29 : 28;
- }
-
- return month_days[month - 1];
-}
-
static void tm_add(struct tm *in, struct tm *out, unsigned long secs)
{
- unsigned long year, month, mday, hour, minute, second, d;
- static const unsigned long sec_in_400_years =
- ((303ul * 365) + (97 * 366)) * 24 * 60 * 60;
-
assert(in);
assert(out);
- second = in->tm_sec;
- minute = in->tm_min;
- hour = in->tm_hour;
- mday = in->tm_mday;
- month = in->tm_mon;
- year = in->tm_year;
-
- second += secs;
-
- /* There are the same number of seconds in any 400-year block; this
- * limits the iterations in the loop below */
- year += 400 * (second / sec_in_400_years);
- second = second % sec_in_400_years;
-
- if (second >= 60) {
- minute += second / 60;
- second = second % 60;
- }
-
- if (minute >= 60) {
- hour += minute / 60;
- minute = minute % 60;
- }
-
- if (hour >= 24) {
- mday += hour / 24;
- hour = hour % 24;
- }
-
- for (d = days_in_month(month, year); mday >= d;
- d = days_in_month(month, year)) {
- month++;
- if (month > 12) {
- month = 1;
- year++;
- }
- mday -= d;
- }
-
- out->tm_year = year;
- out->tm_mon = month;
- out->tm_mday = mday;
- out->tm_hour = hour;
- out->tm_min = minute;
- out->tm_sec = second;
-}
-
-/* MSB is byte 3, LSB is byte 0 */
-static unsigned int bcd_byte(uint32_t bcd, int byteno)
-{
- bcd >>= byteno * 8;
- return (bcd >> 4 & 0xf) * 10 + (bcd & 0xf);
-}
-
-static uint32_t int_to_bcd2(unsigned int x)
-{
- return (((x / 10) << 4) & 0xf0) | (x % 10);
-}
-
-static uint32_t int_to_bcd4(unsigned int x)
-{
- return int_to_bcd2(x / 100) << 8 | int_to_bcd2(x % 100);
-}
-
-static void rtc_to_tm(struct fsp_msg *msg, struct tm *tm)
-{
- uint32_t x;
-
- /* The FSP returns in BCD:
- *
- * | year | month | mday |
- * +------------------------------------+
- * | hour | minute | secs | reserved |
- * +------------------------------------+
- * | microseconds |
- */
- x = msg->data.words[0];
- tm->tm_year = bcd_byte(x, 3) * 100 + bcd_byte(x, 2);
- tm->tm_mon = bcd_byte(x, 1);
- tm->tm_mday = bcd_byte(x, 0);
-
- x = msg->data.words[1];
- tm->tm_hour = bcd_byte(x, 3);
- tm->tm_min = bcd_byte(x, 2);
- tm->tm_sec = bcd_byte(x, 1);
-}
-
-static void tm_to_datetime(struct tm *tm, uint32_t *y_m_d, uint64_t *h_m_s_m)
-{
- uint64_t h_m_s;
- /*
- * The OPAL API is defined as returned a u64 of a similar
- * format to the FSP message; the 32-bit date field is
- * in the format:
- *
- * | year | year | month | day |
- *
- */
- *y_m_d = int_to_bcd4(tm->tm_year) << 16 |
- int_to_bcd2(tm->tm_mon) << 8 |
- int_to_bcd2(tm->tm_mday);
-
- /*
- * ... and the 64-bit time field is in the format
- *
- * | hour | minutes | secs | millisec |
- * | -------------------------------------
- * | millisec | reserved |
- *
- * We simply ignore the microseconds/milliseconds for now
- * as I don't quite understand why the OPAL API defines that
- * it needs 6 digits for the milliseconds :-) I suspect the
- * doc got that wrong and it's supposed to be micro but
- * let's ignore it.
- *
- * Note that Linux doesn't use nor set the ms field anyway.
- */
- h_m_s = int_to_bcd2(tm->tm_hour) << 24 |
- int_to_bcd2(tm->tm_min) << 16 |
- int_to_bcd2(tm->tm_sec) << 8;
-
- *h_m_s_m = h_m_s << 32;
+ *out = *in;
+ out->tm_sec += secs;
+ mktime(out);
}
static void fsp_tpo_req_complete(struct fsp_msg *read_resp)
@@ -313,7 +173,8 @@ static void fsp_rtc_process_read(struct fsp_msg *read_resp)
case FSP_STATUS_SUCCESS:
/* Save the read RTC value in our cache */
- rtc_to_tm(read_resp, &rtc_tod_cache.tm);
+ 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;
break;
@@ -514,7 +375,7 @@ static int64_t fsp_opal_rtc_write(uint32_t year_month_day,
w0 = year_month_day;
w1 = (hour_minute_second_millisecond >> 32) & 0xffffff00;
w2 = 0;
-
+
rtc_write_msg = fsp_mkmsg(FSP_CMD_WRITE_TOD, 3, w0, w1, w2);
if (!rtc_write_msg) {
DBG(" -> allocation failed !\n");
@@ -524,7 +385,8 @@ static int64_t fsp_opal_rtc_write(uint32_t year_month_day,
DBG(" -> req at %p\n", rtc_write_msg);
if (fsp_in_reset) {
- rtc_to_tm(rtc_write_msg, &rtc_tod_cache.tm);
+ 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;
fsp_freemsg(rtc_write_msg);
diff --git a/include/time-utils.h b/include/time-utils.h
new file mode 100644
index 0000000..721b6f7
--- /dev/null
+++ b/include/time-utils.h
@@ -0,0 +1,26 @@
+/* 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 __TIME_UTILS_H
+#define __TIME_UTILS_H
+
+#include <stdint.h>
+#include <time.h>
+
+void tm_to_datetime(struct tm *tm, uint32_t *y_m_d, uint64_t *h_m_s_m);
+void datetime_to_tm(uint32_t y_m_d, uint64_t h_m_s_m, struct tm *tm);
+
+#endif