summaryrefslogtreecommitdiffstats
path: root/src/ssx/ppc405/ppc405_core.c
blob: 5df096717dc13857ecd41176b7aff9f18755cbc5 (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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
// $Id: ppc405_core.c,v 1.1.1.1 2013/12/11 21:03:27 bcbrock Exp $
// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/ssx/ppc405/ppc405_core.c,v $
//-----------------------------------------------------------------------------
// *! (C) Copyright International Business Machines Corp. 2013
// *! All Rights Reserved -- Property of IBM
// *! *** IBM Confidential ***
//-----------------------------------------------------------------------------

/// \file ppc405_core.c
/// \brief The final bits of SSX runtime code required to complete the PPC405
/// port. 
///
/// The entry points in this file are considered 'core' routines that will
/// always be present during runtime in any SSX application.

#define __PPC405_CORE_C__

#include "ssx.h"

/// Get the 64-bit timebase following the PowerPC protocol
///
/// Note that the only way to guarantee that the value returned is the value
/// \e right \e now is to call this API from a critical section.

SsxTimebase
ssx_timebase_get(void) 
{
    Uint64 tb;
    uint32_t high;

    do {
        tb.word[0] = mftbu();
        tb.word[1] = mftb();
        high       = mftbu();
    } while (high != tb.word[0]);

    return tb.value;
}


/// Set the 64-bit timebase in an SSX_CRITICAL 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
ssx_timebase_set(SsxTimebase timebase) 
{
    SsxMachineContext ctx;
    Uint64 tb;

    tb.value = timebase;

    ssx_critical_section_enter(SSX_CRITICAL, &ctx);

    mttbl(0);
    mttbu(tb.word[0]);
    mttbl(tb.word[1]);

    ssx_critical_section_exit(&ctx);
}
    

/// Enable interrupt preemption
///
/// This API can only be called from an interrupt context.  Threads will
/// always be preempted by interrupts unless they explicitly disable
/// interrupts with the \c ssx_interrupt_disable() API. It is legal to call
/// this API redundantly.
///
/// Be careful when enabling interrupt handler preemption that the interrupt
/// being handled does not/can not trigger again, as this could rapidly lead
/// to stack overflows.
///
/// Return values other then SSX_OK (0) are errors; see \ref ssx_errors
///
/// \retval 0 Successful completion
///
/// \retval -SSX_ILLEGAL_CONTEXT The API call was not made from an interrupt
/// context. 

int
ssx_interrupt_preemption_enable()
{
    if (SSX_ERROR_CHECK_API) {
        SSX_ERROR_UNLESS_ANY_INTERRUPT_CONTEXT();
    }

    if (__ssx_kernel_context_noncritical_interrupt()) {
        wrteei(1);
    } else {
        or_msr(MSR_CE);
    }

    return SSX_OK;
}
        

/// Disable interrupt preemption
///
/// This API can only be called from an interrupt context.  Threads will
/// always be preempted by interrupts unless they explicitly disable
/// interrupts with the \c ssx_interrupt_disable() API.  It is legal to call
/// this API redundantly.
///
/// Return values other then SSX_OK (0) are errors; see \ref ssx_errors
///
/// \retval 0 Successful completion
///
/// \retval -SSX_ILLEGAL_CONTEXT The API call was not made from an interrupt
/// context. 

int
ssx_interrupt_preemption_disable()
{
    if (SSX_ERROR_CHECK_API) {
        SSX_ERROR_UNLESS_ANY_INTERRUPT_CONTEXT();
    }

    if (__ssx_kernel_context_noncritical_interrupt()) {
        wrteei(0);
    } else {
        andc_msr(MSR_CE);
    }

    return SSX_OK;
}
        

#if SSX_TIMER_SUPPORT

// The tickless kernel timer mechanism for PPC405
//
// This routine must be called from an SSX_NONCRITICAL 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 - SSX 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
// __ssx_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 SSX specification.

void
__ssx_schedule_hardware_timeout(SsxTimebase timeout)
{
    SsxTimebase now;
    uint32_t pit;

    if (timeout != SSX_TIMEBASE_MAX) {

        now = ssx_timebase_get();

        if (timeout <= now) {
            pit = 1;
        } else if ((timeout - now) > 0xffffffff) {
            pit = 0xffffffff;
        } else {
            pit = timeout - now;
        }

        mtspr(SPRN_PIT, pit);
    }
}


// Cancel the PPC405 tickless kernel timeout
//
// This routine must be called from an SSX_NONCRITICAL critical section.  SSX
// does not use auto-reload mode of the PIT, so simply writing the PIT with 0
// effectively cancels the timer.

void
__ssx_cancel_hardware_timeout()
{
    mtspr(SPRN_PIT, 0);
}


#endif  /* SSX_TIMER_SUPPORT */

#undef __PPC405_CORE_C__
OpenPOWER on IntegriCloud