summaryrefslogtreecommitdiffstats
path: root/pk/gpe/gpe_irq.h
blob: 3b018916af3714ba3a87d60bf6345397e4c2e4f5 (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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
#ifndef __GPE_IRQ_H__
#define __GPE_IRQ_H__

//-----------------------------------------------------------------------------
// *! (C) Copyright International Business Machines Corp. 2014
// *! All Rights Reserved -- Property of IBM
// *! *** IBM Confidential ***
//-----------------------------------------------------------------------------

/// \file occhw_irq.h
/// \brief GPE-OCCHW Interrupt handling for PK
///
/// The OCCHW interrupt controller supports a maximum of 64 interrupts, split
/// into 2 x 32-bit non-cascaded interrupt controllers with simple OR
/// combining of the interrupt signals.
///
/// The OCB interrupt controller allows interrupt status to be set directly by
/// software, as well as providing a mode that causes an enabled pending
/// interrupt to trigger an Unconditional Debug Event. The OCB interrupt
/// controller contains a 'mask' register, unlike other 405 interrupt
/// controllers that have an 'enable' register.  The OCCHW mask and status
/// registers also have atomic CLR/OR function so that it is never necessary
/// to enter a critical section to enable/disable/clear interrupts and
/// interrupt status.

#include "occhw_common.h"
#include "ocb_register_addresses.h"
#include "ppe42.h"

#ifndef __ASSEMBLER__

/// Enable an interrupt by clearing the mask bit.  

UNLESS__PPE42_IRQ_CORE_C__(extern)
inline void
pk_irq_enable(PkIrqId irq)
{
    out32(OCCHW_OIMR_CLR(irq), OCCHW_IRQ_MASK32(irq));
}


/// Disable an interrupt by setting the mask bit.

UNLESS__PPE42_IRQ_CORE_C__(extern)
inline void
pk_irq_disable(PkIrqId irq)
{
    out32(OCCHW_OIMR_OR(irq), OCCHW_IRQ_MASK32(irq));
}


/// Clear interrupt status with an CLR mask.  Only meaningful for
/// edge-triggered interrupts.

UNLESS__PPE42_IRQ_CORE_C__(extern)
inline void
pk_irq_status_clear(PkIrqId irq)
{
    out32(OCCHW_OISR_CLR(irq), OCCHW_IRQ_MASK32(irq));
}


/// Get IRQ status as a 0 or non-0 integer

UNLESS__PPE42_IRQ_CORE_C__(extern)
inline int
pk_irq_status_get(PkIrqId irq)
{
    return (in32(OCCHW_OISR(irq)) & OCCHW_IRQ_MASK32(irq)) != 0;
}


/// Set or clear interrupt status explicitly.

UNLESS__PPE42_IRQ_CORE_C__(extern)
inline void
pk_irq_status_set(PkIrqId irq, int value)
{
    if (value) {
        out32(OCCHW_OISR_OR(irq), OCCHW_IRQ_MASK32(irq));
    } else {
        out32(OCCHW_OISR_CLR(irq), OCCHW_IRQ_MASK32(irq));
    }
}


#endif  /* __ASSEMBLER__ */

/// \page occhw_irq_macros OCCHW IRQ API Assembler Macros
///
/// These macros encapsulate the PK API for the OCCHW interrupt
/// controller. These macros require 2 scratch registers in addition to the \c
/// irq parameter register passed into the handler from PK interrupt
/// dispatch. These macros also modify CR0.
///
/// \arg \c rirq A register that holds the \c irq parameter passed to
///              the handler from PK interrupt dispatch.  This register is not
///              modified. 
/// \arg \c rmask A scratch register - At the end of macro execution this
///               register contains the 32-bit mask form of the irq.
///
/// \arg \c raddr A scratch register - At the end of macro execution this
///               register holds the address of the interrupt 
///               controller facility that implements the action.
///
/// \arg \c imm An immediate (0/non-0) value for certain macros.
///
/// Forms:
/// 
/// \b _pk_irq_enable \a rirq, \a rmask, \a raddr - Enable an \c irq. \n
/// \b _pk_irq_disable \a rirq, \a rmask, \a raddr - Disable an \c irq. \n
/// \b _pk_irq_status_clear \a rirq, \a rmask, \a raddr - Clear \c irq
///                          interrupt status. \n
/// \b _pk_irq_status_set \a rirq, \a rmask, \a raddr, \a imm - Set \c irq status
///                        with an immediate (0/non-0) value. \n
///
/// \todo Once the logic design is locked down, revisit whether these macros
/// (and C-code versions) can be implemented without branching.  This could be
/// done in theory by converting bit 26 into the byte offset between addresses
/// in interupt controller 0 and interrupt controller 1 - assuming the
/// distances are all the same power-of-two.
///
/// \cond

// IRQ numbers are in the range 0..63.  IRQs are converted to the 32-bit
// residue used to compute the mask.  CR0 is set as a test of IRQ > 32 - the
// register \c raddr is used as scratch for these computations.  Hopefully the
// local labels 888 and 999 are unique enough.

// Register names must be compared as strings - e.g., %r0 is not 
// a symbol, it is converted to "0" by the assembler.

#ifdef __ASSEMBLER__

        .macro  .two_unique, ra, rb
        .ifnc   \ra, \rb
        .exitm
        .endif
        .error  "Both register arguments must be unique"
        .endm


        .macro  .three_unique, ra, rb, rc
        .ifnc   \ra, \rb
        .ifnc   \rb, \rc
        .ifnc   \ra, \rc
        .exitm
        .endif
        .endif
        .endif
        .error  "All three register arguments must be unique"
        .endm


        .macro  _occhw_irq_or_mask, rirq:req, rmask:req
        .two_unique \rirq, \rmask
        lis     \rmask, 0x8000
        srw     \rmask, \rmask, \rirq
        .endm

        .macro  _occhw_irq_clr_mask, rirq:req, rmask:req
        .two_unique \rirq, \rmask
        _occhw_irq_or_mask \rirq, \rmask
        .endm


        .macro  _pk_irq_enable, rirq:req, rmask:req, raddr:req
        .three_unique \rirq, \rmask, \raddr
        
        andi.   \raddr, \rirq, 0x20
        clrlwi  \raddr, \rirq, 27
        _occhw_irq_clr_mask \raddr, \rmask
        bne-    888f
        _stwi   \rmask, \raddr, OCB_OIMR0_CLR
        b       999f
888:    
        _stwi   \rmask, \raddr, OCB_OIMR1_CLR
999:            
        eieio
        .endm


        .macro  _pk_irq_disable, rirq:req, rmask:req, raddr:req
        .three_unique \rirq, \rmask, \raddr
        
        andi.   \raddr, \rirq, 0x20
        clrlwi  \raddr, \rirq, 27
        _occhw_irq_or_mask \raddr, \rmask
        bne-    888f
        _stwi   \rmask, \raddr, OCB_OIMR0_OR
        b       999f
888:    
        _stwi   \rmask, \raddr, OCB_OIMR1_OR
999:    
        eieio
        .endm


        .macro  _pk_irq_status_clear, rirq:req, rmask:req, raddr:req
        .three_unique \rirq, \rmask, \raddr
        
        andi.   \raddr, \rirq, 0x20
        clrlwi  \raddr, \rirq, 27
        _occhw_irq_clr_mask \raddr, \rmask
        bne-    888f
        _stwi   \rmask, \raddr, OCB_OISR0_CLR
        b       999f
888:
        _stwi   \rmask, \raddr, OCB_OISR1_CLR
999:            
        eieio
        .endm


        .macro  _pk_irq_status_set, rirq:req, rmask:req, raddr:req, imm:req
        .three_unique \rirq, \rmask, \raddr

        andi.   \raddr, \rirq, 0x20
        clrlwi  \raddr, \rirq, 27
        
        .if     \imm
        _occhw_irq_or_mask \raddr, \rmask
        bne-    888f
        _stwi   \rmask, \raddr, OCB_OISR0_OR
        b       999f
888:    
        _stwi   \rmask, \raddr, OCB_OISR1_OR

        .else
        
        _occhw_irq_clr_mask \raddr, \rmask
        bne-    888f
        _stwi   \rmask, \raddr, OCB_OISR0_CLR
        b       999f
888:
        _stwi   \rmask, \raddr, OCB_OISR1_CLR
        .endif

999:    
        eieio
        .endm

#endif  /* __ASSEMBLER__ */

/// \endcond

#endif /* __GPE_IRQ_H__ */
OpenPOWER on IntegriCloud