summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_core.c
blob: 7b6604b139da1bbe5072b1642d8b881a225911b2 (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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42_core.c $    */
/*                                                                        */
/* OpenPOWER sbe Project                                                  */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2016                        */
/* [+] International Business Machines 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

/// \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__
OpenPOWER on IntegriCloud