blob: 2fa86e6840b4ff69465e06f1b6a500afbb192dfe (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
//-----------------------------------------------------------------------------
// *! (C) Copyright International Business Machines Corp. 2014
// *! All Rights Reserved -- Property of IBM
// *! *** IBM Confidential ***
//-----------------------------------------------------------------------------
/// \file ppe42_core.c
/// \brief The final bits of PK runtime code required to complete the PPE42
/// port.
///
/// The entry points in this file are considered 'core' routines that will
/// always be present during runtime in any PK application.
#define __PPE42_CORE_C__
#include "pk.h"
typedef union
{
uint64_t value;
struct
{
uint32_t dec_start;
uint32_t dec_change_tag;
};
}ppe42_timebase_data_t;
ppe42_timebase_data_t ppe42_tb_data = {0};
PkTimebase ppe42_64bit_timebase = 0;
#if PK_TIMER_SUPPORT
// The tickless kernel timer mechanism for PPE42
//
// This routine must be called from a critical section.
//
// Tickless timeouts are provided by programming the PIT timer based on when
// the next timeout will occur. If the timeout is for the end of time there's
// nothing to do - PK does not use auto-reload mode so no more PIT interrupts
// will be arriving. Otherwise, if the timeout is longer than the 32-bit PIT
// timer can handle, we simply schedule the timeout for 2**32 - 1 and
// __pk_timer_handler() will keep rescheduling it until it finally occurs.
// 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.
#ifndef APPCFG_USE_EXT_TIMEBASE
void
__pk_schedule_hardware_timeout(PkTimebase timeout)
{
PkTimebase now;
uint32_t new_dec;
uint32_t dec;
if (timeout != PK_TIMEBASE_MAX) {
now = pk_timebase_get();
if (timeout <= now) {
new_dec = 1;
} else if ((timeout - now) > 0xffff0000) {
new_dec = 0xffff0000;
} else {
new_dec = timeout - now;
}
//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);
//update our 64bit accumulator with how much time has advanced since
//we last changed it.
ppe42_64bit_timebase += ppe42_tb_data.dec_start - dec;
//update our start time so we know how much time has advanced since
//this update of the accumulator
ppe42_tb_data.dec_start = new_dec;
ppe42_tb_data.dec_change_tag++;
}
}
#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
{
diff = (timeout - now);
if (diff > 0xfffffffful)
{
new_dec = 0xffffffff;
}
else
{
new_dec = diff;
}
}
mtspr(SPRN_DEC, new_dec);
}
}
#endif /* APPCFG_USE_EXT_TIMEBASE */
#endif /* PK_TIMER_SUPPORT */
#undef __PPE42_CORE_C__
|