summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorVasant Hegde <hegdevasant@linux.vnet.ibm.com>2018-04-23 12:15:32 +0530
committerStewart Smith <stewart@linux.ibm.com>2018-04-30 19:04:42 -0500
commitd7e7bdcd4accff9fb75579b43be72bc3c201d161 (patch)
tree0641e6c0ec772449322c053024a70da759d51a24 /core
parent6421fc56dc289c8d14a1ce9eddbb88d3687fbb77 (diff)
downloadtalos-skiboot-d7e7bdcd4accff9fb75579b43be72bc3c201d161.tar.gz
talos-skiboot-d7e7bdcd4accff9fb75579b43be72bc3c201d161.zip
SBE: Add timer support
SBE on P9 provides one shot programmable timer facility. We can use this to implement OPAL timers and hence limit the reliance on the Linux heartbeat (similar to HW timer facility provided by SLW on P8). Design: - We will continue to run Linux heartbeat. - Each chip has SBE. This patch always schedules timer on SBE on master chip. - Start timer option starts new timer or modifies an active timer for the specified timeout. - SBE expects timeout value in microseconds. We track timeout value in TB. Hence we convert tb to microseconds before sending request to SBE. - We are requesting ack from SBE for timer message. It gaurantees that SBE has scheduled timer. - Disabling SBE timer We expect SBE to send timer expiry interrupt whenever timer expires. We wait for 10 more ms before disabling timer. In future we can consider below alternative approaches: - Presently SBE timer disable is permanent (until we reboot system). SBE sends "I'm back" interrupt after reset. We can consider restarting timer after SBE reset. - Reset SBE and start timer again. - Each chip has SBE. On multi chip system we can try to schedule timer on different chip. Signed-off-by: Vasant Hegde <hegdevasant@linux.vnet.ibm.com> CC: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Stewart Smith <stewart@linux.ibm.com>
Diffstat (limited to 'core')
-rw-r--r--core/interrupts.c3
-rw-r--r--core/test/run-timer.c8
-rw-r--r--core/timer.c17
3 files changed, 24 insertions, 4 deletions
diff --git a/core/interrupts.c b/core/interrupts.c
index 4452511f..5d7a68cd 100644
--- a/core/interrupts.c
+++ b/core/interrupts.c
@@ -26,6 +26,7 @@
#include <ccan/str/str.h>
#include <timer.h>
#include <sbe-p8.h>
+#include <sbe-p9.h>
/* ICP registers */
#define ICP_XIRR 0x4 /* 32-bit access */
@@ -489,7 +490,7 @@ static int64_t opal_handle_interrupt(uint32_t isn, __be64 *outstanding_event_mas
is->ops->interrupt(is, isn);
/* Check timers if SBE timer isn't working */
- if (!p8_sbe_timer_ok())
+ if (!p8_sbe_timer_ok() && !p9_sbe_timer_ok())
check_timers(true);
/* Update output events */
diff --git a/core/test/run-timer.c b/core/test/run-timer.c
index 986af28d..159e007a 100644
--- a/core/test/run-timer.c
+++ b/core/test/run-timer.c
@@ -4,12 +4,15 @@
#define __TEST__
#include <timer.h>
+#include <skiboot.h>
#define mftb() (stamp)
#define sync()
#define smt_lowest()
#define smt_medium()
+enum proc_gen proc_gen = proc_gen_p9;
+
static uint64_t stamp, last;
struct lock;
static inline void lock_caller(struct lock *l, const char *caller)
@@ -53,6 +56,11 @@ void p8_sbe_update_timer_expiry(uint64_t new_target)
/* FIXME: do intersting SLW timer sim */
}
+void p9_sbe_update_timer_expiry(uint64_t new_target)
+{
+ (void)new_target;
+}
+
int main(void)
{
unsigned int i;
diff --git a/core/timer.c b/core/timer.c
index 21f62a49..8eefb74b 100644
--- a/core/timer.c
+++ b/core/timer.c
@@ -5,6 +5,7 @@
#include <device.h>
#include <opal.h>
#include <sbe-p8.h>
+#include <sbe-p9.h>
#ifdef __TEST__
#define this_cpu() ((void *)-1)
@@ -109,8 +110,12 @@ static void __schedule_timer_at(struct timer *t, uint64_t when)
bail:
/* Pick up the next timer and upddate the SBE HW timer */
lt = list_top(&timer_list, struct timer, link);
- if (lt)
- p8_sbe_update_timer_expiry(lt->target);
+ if (lt) {
+ if (proc_gen < proc_gen_p9)
+ p8_sbe_update_timer_expiry(lt->target);
+ else
+ p9_sbe_update_timer_expiry(lt->target);
+ }
}
void schedule_timer_at(struct timer *t, uint64_t when)
@@ -167,7 +172,11 @@ static void __check_poll_timers(uint64_t now)
* arbitrarily 1us.
*/
if (t->running) {
- p8_sbe_update_timer_expiry(now + usecs_to_tb(1));
+ if (proc_gen < proc_gen_p9)
+ p8_sbe_update_timer_expiry(now + usecs_to_tb(1));
+ else
+ p9_sbe_update_timer_expiry(now + usecs_to_tb(1));
+
break;
}
@@ -266,6 +275,8 @@ void late_init_timers(void)
*/
if (platform.heartbeat_time) {
heartbeat = platform.heartbeat_time();
+ } else if (p9_sbe_timer_ok()) {
+ heartbeat = HEARTBEAT_DEFAULT_MS * 10;
} else if (p8_sbe_timer_ok() || fsp_present()) {
heartbeat = HEARTBEAT_DEFAULT_MS * 10;
}
OpenPOWER on IntegriCloud