summaryrefslogtreecommitdiffstats
path: root/pk
diff options
context:
space:
mode:
Diffstat (limited to 'pk')
-rw-r--r--pk/gpe/gpe_timebase.h44
-rw-r--r--pk/gpe/pk_port.h2
-rw-r--r--pk/kernel/pk_api.h7
-rw-r--r--pk/kernel/pk_init.c9
-rw-r--r--pk/ppe/pk_port.h1
-rw-r--r--pk/ppe/ppe_timebase.h28
-rw-r--r--pk/ppe42/ppe42_core.c100
-rw-r--r--pk/ppe42/ppe42_init.c19
-rw-r--r--pk/ppe42/ppe42_timebase.S60
-rw-r--r--pk/std/pk_port.h1
-rw-r--r--pk/std/std_timebase.h46
-rw-r--r--pk/trace/pk_trace.h3
-rw-r--r--pk/trace/pk_trace_core.c58
13 files changed, 243 insertions, 135 deletions
diff --git a/pk/gpe/gpe_timebase.h b/pk/gpe/gpe_timebase.h
new file mode 100644
index 00000000..3c27bdfb
--- /dev/null
+++ b/pk/gpe/gpe_timebase.h
@@ -0,0 +1,44 @@
+#ifndef __GPE_TIMEBASE_H__
+#define __GPE_TIMEBASE_H__
+
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2015
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file gpe_timebase.h
+/// \brief support for using the OCB 32 bit timebase register
+///
+/// The OCB timebase register is a 32 bit count-up register that is shared
+/// by all GPE's in the OCC complex.
+
+#include "pk.h"
+
+//The timebase register is not yet supported in the OCB model.
+//remove this line once it is supported.
+#define APPCFG_USE_DEC_FOR_TIMEBASE
+
+#ifndef __ASSEMBLER__
+
+#ifndef APPCFG_USE_DEC_FOR_TIMEBASE
+static inline
+uint32_t pk_timebase32_get(void)
+{
+ return in32(OCB_OTBR);
+}
+
+#else
+//assembly function is defined in ppe42_timebase.S
+uint32_t pk_timebase32_get(void);
+
+#endif /* APPCFG_USE_DEC_FOR_TIMEBASE */
+
+#else
+
+ .macro _pk_timebase32_get rT, rA
+ _lwzi \rT, \rA, OCB_OTBR
+ .endm
+#endif /* __ASSEMBLER__ */
+
+#endif /* __GPE_TIMEBASE_H__ */
diff --git a/pk/gpe/pk_port.h b/pk/gpe/pk_port.h
index 887c123e..410f4356 100644
--- a/pk/gpe/pk_port.h
+++ b/pk/gpe/pk_port.h
@@ -12,5 +12,5 @@
#define HWMACRO_GPE
#include "ppe42.h"
-
+#include "gpe_timebase.h"
#endif /* __PK_PORT_H__ */
diff --git a/pk/kernel/pk_api.h b/pk/kernel/pk_api.h
index b0e7419c..51440275 100644
--- a/pk/kernel/pk_api.h
+++ b/pk/kernel/pk_api.h
@@ -671,9 +671,6 @@ pk_initialize(PkAddress noncritical_stack,
PkTimebase
pk_timebase_get(void);
-void
-pk_timebase_set(PkTimebase timebase);
-
// Interrupt preemption APIs
int
@@ -930,11 +927,13 @@ pk_deque_delete(PkDeque *element)
element->next = 0;
}
-
+//Trace function prototypes
void pk_trace_tiny(uint32_t i_parm);
void pk_trace_big(uint32_t i_hash_and_count,
uint64_t i_parm1, uint64_t i_parm2);
void pk_trace_binary(uint32_t i_hash_and_size, void* bufp);
+void pk_trace_set_timebase(PkTimebase timebase);
+
/// Cast a pointer to another type, in a way that won't cause warnings
diff --git a/pk/kernel/pk_init.c b/pk/kernel/pk_init.c
index 9174e51d..2ac06f33 100644
--- a/pk/kernel/pk_init.c
+++ b/pk/kernel/pk_init.c
@@ -68,10 +68,6 @@ pk_initialize(PkAddress noncritical_stack,
PK_INVALID_ARGUMENT_INIT);
}
- if (initial_timebase != PK_TIMEBASE_CONTINUES) {
- pk_timebase_set(initial_timebase);
- }
-
__pk_timebase_frequency_hz = timebase_frequency_hz;
__pk_timebase_frequency_khz = timebase_frequency_hz / 1000;
__pk_timebase_frequency_mhz = timebase_frequency_hz / 1000000;
@@ -108,8 +104,9 @@ extern PkTraceBuffer g_pk_trace_buf;
//set the trace timebase HZ
g_pk_trace_buf.hz = timebase_frequency_hz;
- //TODO: set the ppe instance id (for CME's)
-
+ //set the timebase ajdustment for trace synchronization
+ pk_trace_set_timebase(initial_timebase);
+
#endif /* PK_TRACE_SUPPORT */
#endif /* PK_TIMER_SUPPORT */
diff --git a/pk/ppe/pk_port.h b/pk/ppe/pk_port.h
index f9010581..b88078f2 100644
--- a/pk/ppe/pk_port.h
+++ b/pk/ppe/pk_port.h
@@ -12,5 +12,6 @@
#define HWMACRO_PPE
#include "ppe42.h"
+#include "ppe_timebase.h"
#endif /* __PK_PORT_H__ */
diff --git a/pk/ppe/ppe_timebase.h b/pk/ppe/ppe_timebase.h
new file mode 100644
index 00000000..f3d2c91d
--- /dev/null
+++ b/pk/ppe/ppe_timebase.h
@@ -0,0 +1,28 @@
+#ifndef __PPE_TIMEBASE_H__
+#define __PPE_TIMEBASE_H__
+
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2015
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file gpe_timebase.h
+/// \brief support for using the OCB 32 bit timebase register
+///
+/// The OCB timebase register is a 32 bit count-up register that is shared
+/// by all GPE's in the OCC complex.
+
+#include "pk.h"
+
+//The timebase register will never be supported in the base ppe model
+#define APPCFG_USE_DEC_FOR_TIMEBASE
+
+#ifndef __ASSEMBLER__
+
+//assembly function is defined in ppe42_timebase.S
+uint32_t pk_timebase32_get(void);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* __PPE_TIMEBASE_H__ */
diff --git a/pk/ppe42/ppe42_core.c b/pk/ppe42/ppe42_core.c
index f82b3bf6..6586888c 100644
--- a/pk/ppe42/ppe42_core.c
+++ b/pk/ppe42/ppe42_core.c
@@ -29,56 +29,6 @@ ppe42_timebase_data_t ppe42_tb_data = {0};
PkTimebase ppe42_64bit_timebase = 0;
-#if 0
-/// Get the emulated 64-bit timebase
-///
-
-PkTimebase
-pk_timebase_get(void)
-{
- PkTimebase tb;
- uint32_t dec_start;
- uint32_t dec;
- uint32_t time_since_last_update;
- PkMachineContext ctx;
-
- pk_critical_section_enter(&ctx);
-
- tb = ppe42_64bit_timebase;
- dec_start = ppe42_dec_start;
- dec = mfspr(SPRN_DEC);
-
- pk_critical_section_exit(&ctx);
-
- time_since_last_update = dec_start - dec;
-
- return (tb + time_since_last_update);
-}
-#endif
-
-/// Set the 64-bit timebase in an critical section
-///
-/// It is assumed that the caller knows what they are doing; e.g., is aware of
-/// what may happen when time warps as a result of this call.
-
-void
-pk_timebase_set(PkTimebase timebase)
-{
- PkMachineContext ctx;
-
- pk_critical_section_enter(&ctx);
-
- ppe42_64bit_timebase = timebase;
- ppe42_tb_data.dec_start = 0;
- ppe42_tb_data.dec_change_tag++;
-
- //This will cause TSR[DIS] to be set on the next timer tick.
- mtspr(SPRN_DEC, 0);
-
- pk_critical_section_exit(&ctx);
-}
-
-
/// Enable interrupt preemption
///
/// This API can only be called from an interrupt context. Threads will
@@ -152,18 +102,16 @@ pk_interrupt_preemption_disable()
// If the \a timeout is in the past, we schedule the PIT interrupt for 1 tick
// in the future in accordance with the PK specification.
+#ifdef APPCFG_USE_DEC_FOR_TIMEBASE
void
__pk_schedule_hardware_timeout(PkTimebase timeout)
{
PkTimebase now;
uint32_t new_dec;
- PkMachineContext ctx;
uint32_t dec;
if (timeout != PK_TIMEBASE_MAX) {
- pk_critical_section_enter(&ctx);
-
now = pk_timebase_get();
if (timeout <= now) {
@@ -174,7 +122,7 @@ __pk_schedule_hardware_timeout(PkTimebase timeout)
new_dec = timeout - now;
}
- //read and write the DEC back-to-back so that we loose as little time
+ //read and write the DEC back-to-back so that we lose as little time
//as possible
dec = mfspr(SPRN_DEC);
mtspr(SPRN_DEC, new_dec);
@@ -187,12 +135,52 @@ __pk_schedule_hardware_timeout(PkTimebase timeout)
//this update of the accumulator
ppe42_tb_data.dec_start = new_dec;
ppe42_tb_data.dec_change_tag++;
-
- pk_critical_section_exit(&ctx);
}
}
+#else
+
+void
+__pk_schedule_hardware_timeout(PkTimebase timeout)
+{
+ PkTimebase now;
+ PkTimebase diff;
+ uint32_t new_dec;
+
+ if (timeout != PK_TIMEBASE_MAX) {
+
+ now = pk_timebase_get();
+
+ //update our 64bit accumulator with the current snapshot
+ ppe42_64bit_timebase = now;
+
+ if (timeout <= now)
+ {
+ new_dec = 1;
+ }
+ else
+ {
+ //FIXME: We have to multiply the difference by 16
+ //to workaround missing support for selecting the
+ //external dec_timer clock source for the decrementer.
+ diff = (timeout - now) << 4;
+
+ if (diff > 0xfffffffful)
+ {
+ new_dec = 0xffffffff;
+ }
+ else
+ {
+ new_dec = diff;
+ }
+ }
+
+ mtspr(SPRN_DEC, new_dec);
+
+ }
+}
+#endif /* APPCFG_USE_DEC_FOR_TIMEBASE */
#endif /* PK_TIMER_SUPPORT */
diff --git a/pk/ppe42/ppe42_init.c b/pk/ppe42/ppe42_init.c
index 2e4a2ad2..0beea37d 100644
--- a/pk/ppe42/ppe42_init.c
+++ b/pk/ppe42/ppe42_init.c
@@ -50,15 +50,16 @@ __ppe42_system_setup()
*/
#endif /*STATIC_IRQ_TABLE*/
- // Set the DEC to decrement on every cycle and enable the DEC interrupt. Clear the status
- // of all timers for good measure.
-
- //andc_spr(SPRN_TCR, TCR_DS);
- //or_spr(SPRN_TCR, TCR_DIE);
-
- //Use dec_timer signal for decrementer
- or_spr(SPRN_TCR, TCR_DIE | TCR_DS);
- or_spr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS);
+ //Clear all status bits in the TSR
+ mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS);
+
+#ifndef APPCFG_USE_DEC_FOR_TIMEBASE
+ //Enable the DEC interrupt and configure it to use the external dec_timer signal
+ mtspr(SPRN_TCR, TCR_DIE | TCR_DS);
+#else
+ //Enable the DEC interrupt and configure it to use the internal clock signal
+ mtspr(SPRN_TCR, TCR_DIE);
+#endif /* APPCFG_USE_DEC_FOR_TIMEBASE */
#if PK_TIMER_SUPPORT
#if PK_TRACE_SUPPORT
diff --git a/pk/ppe42/ppe42_timebase.S b/pk/ppe42/ppe42_timebase.S
index 16c59529..43d64bb4 100644
--- a/pk/ppe42/ppe42_timebase.S
+++ b/pk/ppe42/ppe42_timebase.S
@@ -23,7 +23,43 @@ pk_timebase_get(void);
.global ppe42_tb_data
.global_function pk_timebase_get
-//Use the DEC for our timebase until we have a real timebase register (uses 9 instructions)
+#ifdef APPCFG_USE_DEC_FOR_TIMEBASE
+
+ /// Note that it is ok to use this function in a fast interrupt
+ /// context
+ .align 5
+ .global_function pk_timebase32_get
+pk_timebase32_get:
+
+ //load the decrementer start time and change tag
+ lvd %r4, ppe42_tb_data@sda21(0)
+
+ //load the lower 32 bits of the 64bit timebase accumulator
+ lwz %r3, ppe42_64bit_timebase+4@sda21(0)
+
+ //load the current decrementer value
+ mfdec %r0
+
+ //load the change tag again (should already be in the cache)
+ lwz %r6, ppe42_tb_data+4@sda21(0)
+
+ //loop until the change tag is the same (typically should be same)
+ cmplwbne %r5, %r6, pk_timebase32_get
+
+ //calculate how much time has passed since the decrementer was started and store in r6
+ subf %r5, %r0, %r4
+
+ //add the 32bit difference to our 32bit timebase accumulator
+ add %r3, %r5, %r3
+
+ blr
+
+
+/// Use the DEC for our timebase until we have a real timebase register (uses
+/// 9 instructions).
+/// Note: It is not ok to use this function in a fast interrupt context due to
+/// its use of r7
+ .align 5
pk_timebase_get:
//load the decrementer start time and change tag
@@ -40,9 +76,7 @@ pk_timebase_get:
lwz %r7, ppe42_tb_data+4@sda21(0)
//loop until the change tag is the same
- //cmplwbne %r6, %r7, pk_timebase_get
- cmplw %r6, %r7
- bne pk_timebase_get
+ cmplwbne %r6, %r7, pk_timebase_get
//calculate how much time has passed since the decrementer was started and store in r6
subf %r6, %r0, %r5
@@ -54,28 +88,28 @@ pk_timebase_get:
blr
//enable this once we have a local timebase register in the model
-#if 0
+#else
// use the local timebase register to keep more accurate time with just 6 instructions
// in the common case and 7 otherwise.
+ .align 5
pk_timebase_get:
- //load the timebase local 32bit register address
- lwz r5, timebase_local_reg@sda21(0)
-
//load the 64bit timebase accumulator
- lvd r3, ppe42_64bit_timebase@sda21(0)
+ lvd r3, ppe42_64bit_timebase@sda21(0)
- //read the local timebase register
- lwz r5, 0(r5)
+ //read the local timebase register (2 instructions)
+ _pk_timebase32_get r5, r5
//increment the upper 32 bits if the lower 32 bits have flipped
cmplwbgt r5, r4, update_lower_32
- addi r3, 1 //update upper 32
+
+ //increment the upper 32 bits
+ addi r3, r3, 1
update_lower_32:
//replace the lower 32bits with what we read from the local timebase register
- mr r4, r6
+ mr r4, r5
blr
#endif
diff --git a/pk/std/pk_port.h b/pk/std/pk_port.h
index 5998bd4b..4d400cc5 100644
--- a/pk/std/pk_port.h
+++ b/pk/std/pk_port.h
@@ -12,5 +12,6 @@
#define HWMACRO_STD
#include "ppe42.h"
+#include "std_timebase.h"
#endif /* __PK_PORT_H__ */
diff --git a/pk/std/std_timebase.h b/pk/std/std_timebase.h
new file mode 100644
index 00000000..e88a9bc6
--- /dev/null
+++ b/pk/std/std_timebase.h
@@ -0,0 +1,46 @@
+#ifndef __STD_TIMEBASE_H__
+#define __STD_TIMEBASE_H__
+
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2015
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file std_timebase.h
+/// \brief support for using the standard PPE 32 bit timebase register
+///
+/// Each standard PPE has it's own timebase register that runs at a constant
+/// frequency.
+
+#include "pk.h"
+
+//The timebase register is not yet supported in the STD model.
+//remove this line once it is supported.
+#define APPCFG_USE_DEC_FOR_TIMEBASE
+
+#ifndef __ASSEMBLER__
+
+#ifndef APPCFG_USE_DEC_FOR_TIMEBASE
+static inline
+uint32_t pk_timebase32_get(void)
+{
+ return (uint32_t)((in64(STD_LCL_TBR)) >> 32);
+}
+
+#else
+//assembly function is defined in ppe42_timebase.S
+uint32_t pk_timebase32_get(void);
+
+#endif /* APPCFG_USE_DEC_FOR_TIMEBASE */
+
+#else
+
+ .macro _pk_timebase32_get rT, rA
+ lis \rA, STD_LCL_TBR@ha
+ lvd \rT, STD_LCL_TBR@l(\rA)
+ .endm
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* __STD_TIMEBASE_H__ */
diff --git a/pk/trace/pk_trace.h b/pk/trace/pk_trace.h
index 14a7278b..bcb1ce06 100644
--- a/pk/trace/pk_trace.h
+++ b/pk/trace/pk_trace.h
@@ -12,7 +12,7 @@
#include <stdint.h>
-#define PK_TRACE_VERSION 1
+#define PK_TRACE_VERSION 2
#ifndef PK_TRACE_SZ
#define PK_TRACE_SZ 256
@@ -263,6 +263,7 @@ typedef struct
uint32_t max_time_change;
uint32_t hz;
uint32_t pad;
+ uint64_t time_adj64;
//updated with each new trace entry
PkTraceState state;
diff --git a/pk/trace/pk_trace_core.c b/pk/trace/pk_trace_core.c
index 3f416c75..90a1a36c 100644
--- a/pk/trace/pk_trace_core.c
+++ b/pk/trace/pk_trace_core.c
@@ -42,6 +42,7 @@ PkTraceBuffer g_pk_trace_buf =
.size = PK_TRACE_SZ,
.max_time_change = PK_TRACE_MTBT,
.hz = 500000000, //default value. Actual value is set in pk_init.c
+ .time_adj64 = 0,
.state.word64 = 0,
.cb = {0}
};
@@ -96,52 +97,8 @@ void pk_trace_tiny(uint32_t i_parm)
void pk_trace_timer_callback(void* arg)
{
-#if 0
- PkTraceTime64_t footer;
- PkTraceState state;
- uint64_t* ptr64;
- PkMachineContext ctx;
-
-#define TIMESTAMP64_EXISTS 0x80000000
-
- //If the timestamp64 flag is not set then we need another 64 bit timestamp
- if(!(g_pk_trace_buf.state.tbu32 & TIMESTAMP64_EXISTS))
- {
-
- //fill in the footer data
- footer.word64 = pk_timebase_get();
- footer.time_format.format = PK_TRACE_FORMAT_TIME64;
-
- state.tbu32 = footer.upper32 | TIMESTAMP64_EXISTS;
-
- //The following operations must be done atomically
- pk_critical_section_enter(&ctx);
-
- //load the current byte count and calculate the address for this
- //entry in the cb
- ptr64 = (uint64_t*)&g_pk_trace_buf.cb[g_pk_trace_buf.state.offset & PK_TRACE_CB_MASK];
-
- //calculate the offset for the next entry in the cb
- state.offset = g_pk_trace_buf.state.offset + sizeof(PkTraceTiny);
-
- //update the cb state (tbu and offset)
- g_pk_trace_buf.state.word64 = state.word64;
-
- //write the 64bit timestamp to the buffer
- *ptr64 = footer.word64;
-
- //exit the critical section
- pk_critical_section_exit(&ctx);
-
- }
-
-#else
-
- // doing it this way requires less code, but it also means that the
- // trace can fill up with these traces over time.
-
+ // guarantee at least one trace before the lower 32bit timebase flips
PK_TRACE("PERIODIC TIMESTAMPING TRACE");
-#endif
// restart the timer
pk_timer_schedule(&g_pk_trace_timer,
@@ -149,4 +106,15 @@ void pk_trace_timer_callback(void* arg)
0);
}
+// Use this function to synchronize the timebase between multiple PPEs.
+// PPE A can send PPE B it's current timebase and then PPE B can set that
+// as the current timebase for tracing purposes. It can also be used
+// to set the current time to 0. This function changes the timebase for
+// all entries that are currently in the trace buffer. Setting the current
+// timebase to 0 will cause previous traces to have very large timestamps.
+void pk_trace_set_timebase(PkTimebase timebase)
+{
+ g_pk_trace_buf.time_adj64 = timebase - pk_timebase_get();
+}
+
#endif
OpenPOWER on IntegriCloud