summaryrefslogtreecommitdiffstats
path: root/pk/ppe42/ppe42_core.c
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__
OpenPOWER on IntegriCloud