diff options
Diffstat (limited to 'hw/ipmi/ipmi-rtc.c')
-rw-r--r-- | hw/ipmi/ipmi-rtc.c | 117 |
1 files changed, 90 insertions, 27 deletions
diff --git a/hw/ipmi/ipmi-rtc.c b/hw/ipmi/ipmi-rtc.c index 52da294..9373e89 100644 --- a/hw/ipmi/ipmi-rtc.c +++ b/hw/ipmi/ipmi-rtc.c @@ -8,17 +8,29 @@ #include <stdlib.h> #include <string.h> #include <ipmi.h> +#include <lock.h> #include <time.h> #include <time-utils.h> #include <device.h> #include <opal.h> #include <rtc.h> -static enum {idle, waiting, updated, error} time_status; +static struct lock time_lock = LOCK_UNLOCKED; +static enum { + idle, + waiting, + read_updated, + write_success, + read_error, + write_error, + write_wrong_state, +} time_status; static void get_sel_time_error(struct ipmi_msg *msg) { - time_status = error; + lock(&time_lock); + time_status = read_error; + unlock(&time_lock); ipmi_free_msg(msg); } @@ -31,8 +43,31 @@ static void get_sel_time_complete(struct ipmi_msg *msg) memcpy(&result, msg->data, 4); time = le32_to_cpu(result); gmtime_r(&time, &tm); + lock(&time_lock); rtc_cache_update(&tm); - time_status = updated; + time_status = read_updated; + unlock(&time_lock); + ipmi_free_msg(msg); +} + +static void set_sel_time_error(struct ipmi_msg *msg) +{ + lock(&time_lock); + if (msg->cc == IPMI_NOT_IN_MY_STATE_ERR) { + /* BMC in NTP mode does not allow this */ + time_status = write_wrong_state; + } else { + time_status = write_error; + } + unlock(&time_lock); + ipmi_free_msg(msg); +} + +static void set_sel_time_complete(struct ipmi_msg *msg) +{ + lock(&time_lock); + time_status = write_success; + unlock(&time_lock); ipmi_free_msg(msg); } @@ -55,49 +90,52 @@ static int64_t ipmi_set_sel_time(uint32_t _tv) struct ipmi_msg *msg; const le32 tv = cpu_to_le32(_tv); - msg = ipmi_mkmsg_simple(IPMI_SET_SEL_TIME, (void*)&tv, sizeof(tv)); + msg = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE, IPMI_SET_SEL_TIME, + set_sel_time_complete, NULL, (void *)&tv, sizeof(tv), 0); if (!msg) return OPAL_HARDWARE; + msg->error = set_sel_time_error; + return ipmi_queue_msg(msg); } static int64_t ipmi_opal_rtc_read(__be32 *__ymd, __be64 *__hmsm) { - int ret = 0; uint32_t ymd; uint64_t hmsm; if (!__ymd || !__hmsm) return OPAL_PARAMETER; - switch(time_status) { + lock(&time_lock); + switch (time_status) { case idle: - if (ipmi_get_sel_time() < 0) - return OPAL_HARDWARE; time_status = waiting; - ret = OPAL_BUSY_EVENT; - break; - - case waiting: - ret = OPAL_BUSY_EVENT; - break; - - case updated: + unlock(&time_lock); + return ipmi_get_sel_time(); + case read_updated: rtc_cache_get_datetime(&ymd, &hmsm); *__ymd = cpu_to_be32(ymd); *__hmsm = cpu_to_be64(hmsm); time_status = idle; - ret = OPAL_SUCCESS; - break; - - case error: + unlock(&time_lock); + return OPAL_SUCCESS; + case waiting: + unlock(&time_lock); + return OPAL_BUSY_EVENT; + case read_error: + time_status = idle; + unlock(&time_lock); + return OPAL_HARDWARE; + default: + /* Clear out stale write status */ time_status = idle; - ret = OPAL_HARDWARE; - break; + unlock(&time_lock); + return OPAL_BUSY; } - return ret; + return OPAL_INTERNAL_ERROR; } static int64_t ipmi_opal_rtc_write(uint32_t year_month_day, @@ -106,12 +144,37 @@ static int64_t ipmi_opal_rtc_write(uint32_t year_month_day, time_t t; struct tm tm; - datetime_to_tm(year_month_day, hour_minute_second_millisecond, &tm); - t = mktime(&tm); - if (ipmi_set_sel_time(t)) + lock(&time_lock); + switch (time_status) { + case idle: + time_status = waiting; + unlock(&time_lock); + datetime_to_tm(year_month_day, hour_minute_second_millisecond, &tm); + t = mktime(&tm); + return ipmi_set_sel_time(t); + case write_success: + time_status = idle; + unlock(&time_lock); + return OPAL_SUCCESS; + case waiting: + unlock(&time_lock); + return OPAL_BUSY_EVENT; + case write_error: + time_status = idle; + unlock(&time_lock); return OPAL_HARDWARE; + case write_wrong_state: + time_status = idle; + unlock(&time_lock); + return OPAL_WRONG_STATE; + default: + /* Clear out stale read status */ + time_status = idle; + unlock(&time_lock); + return OPAL_BUSY; + } - return OPAL_SUCCESS; + return OPAL_INTERNAL_ERROR; } void ipmi_rtc_init(void) |