sl@0
|
1 |
// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
|
sl@0
|
2 |
// All rights reserved.
|
sl@0
|
3 |
// This component and the accompanying materials are made available
|
sl@0
|
4 |
// under the terms of the License "Eclipse Public License v1.0"
|
sl@0
|
5 |
// which accompanies this distribution, and is available
|
sl@0
|
6 |
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
|
sl@0
|
7 |
//
|
sl@0
|
8 |
// Initial Contributors:
|
sl@0
|
9 |
// Nokia Corporation - initial contribution.
|
sl@0
|
10 |
//
|
sl@0
|
11 |
// Contributors:
|
sl@0
|
12 |
//
|
sl@0
|
13 |
// Description:
|
sl@0
|
14 |
// e32\nkernsmp\x86\ncirq.cpp
|
sl@0
|
15 |
//
|
sl@0
|
16 |
//
|
sl@0
|
17 |
|
sl@0
|
18 |
/**
|
sl@0
|
19 |
@file
|
sl@0
|
20 |
@internalTechnology
|
sl@0
|
21 |
*/
|
sl@0
|
22 |
|
sl@0
|
23 |
#include "nk_priv.h"
|
sl@0
|
24 |
#include "nk_plat.h"
|
sl@0
|
25 |
#include <nk_irq.h>
|
sl@0
|
26 |
#include <apic.h>
|
sl@0
|
27 |
|
sl@0
|
28 |
#ifdef _DEBUG
|
sl@0
|
29 |
#define DMEMDUMP(base,size) DbgMemDump((TLinAddr)base,size)
|
sl@0
|
30 |
void DbgMemDump(TLinAddr aBase, TInt aSize)
|
sl@0
|
31 |
{
|
sl@0
|
32 |
TInt off;
|
sl@0
|
33 |
const TUint8* p=(const TUint8*)aBase;
|
sl@0
|
34 |
NKern::Lock();
|
sl@0
|
35 |
for (off=0; off<aSize; off+=16, p+=16)
|
sl@0
|
36 |
{
|
sl@0
|
37 |
DEBUGPRINT("%08x: %02x %02x %02x %02x %02x %02x %02x %02x | %02x %02x %02x %02x %02x %02x %02x %02x",
|
sl@0
|
38 |
p, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
|
sl@0
|
39 |
p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
|
sl@0
|
40 |
}
|
sl@0
|
41 |
NKern::Unlock();
|
sl@0
|
42 |
}
|
sl@0
|
43 |
#else
|
sl@0
|
44 |
#define DMEMDUMP(base,size)
|
sl@0
|
45 |
#endif
|
sl@0
|
46 |
|
sl@0
|
47 |
#define IO_APIC_BASE 0xFEC00000
|
sl@0
|
48 |
#define IO_APIC_REGSEL_OFFSET 0x00
|
sl@0
|
49 |
#define IO_APIC_IOWIN_OFFSET 0x10
|
sl@0
|
50 |
|
sl@0
|
51 |
#define IO_APIC_REG_ID 0x00
|
sl@0
|
52 |
#define IO_APIC_REG_VER 0x01
|
sl@0
|
53 |
#define IO_APIC_REG_ARB 0x02
|
sl@0
|
54 |
|
sl@0
|
55 |
#define IO_APIC_CTRL_IMASK 0x10000 // 1 = masked
|
sl@0
|
56 |
#define IO_APIC_CTRL_LEVEL 0x08000 // 1 = level triggered, 0 = edge
|
sl@0
|
57 |
#define IO_APIC_CTRL_REMOTE_IRR 0x04000 //
|
sl@0
|
58 |
#define IO_APIC_CTRL_INTPOL_LOW 0x02000 // 1 = active low
|
sl@0
|
59 |
#define IO_APIC_CTRL_DELIVS 0x01000 //
|
sl@0
|
60 |
#define IO_APIC_CTRL_DESTMOD 0x00800 // 1 = logical, 0 = physical
|
sl@0
|
61 |
#define IO_APIC_CTRL_DELMOD_MASK 0x00700
|
sl@0
|
62 |
#define IO_APIC_CTRL_DELMOD_FIXED 0x00000
|
sl@0
|
63 |
#define IO_APIC_CTRL_DELMOD_LOWP 0x00100
|
sl@0
|
64 |
#define IO_APIC_CTRL_DELMOD_SMI 0x00200
|
sl@0
|
65 |
#define IO_APIC_CTRL_DELMOD_NMI 0x00400
|
sl@0
|
66 |
#define IO_APIC_CTRL_DELMOD_INIT 0x00500
|
sl@0
|
67 |
#define IO_APIC_CTRL_DELMOD_EXTINT 0x00700
|
sl@0
|
68 |
#define IO_APIC_CTRL_INTVEC_MASK 0x000FF
|
sl@0
|
69 |
|
sl@0
|
70 |
|
sl@0
|
71 |
/******************************************************************************
|
sl@0
|
72 |
* IO APIC
|
sl@0
|
73 |
******************************************************************************/
|
sl@0
|
74 |
|
sl@0
|
75 |
#define IO_APIC_SELECT(x) ((void)(*(volatile TUint32*)(iAddr + IO_APIC_REGSEL_OFFSET) = (x)))
|
sl@0
|
76 |
#define IO_APIC_REG (*(volatile TUint32*)(iAddr + IO_APIC_IOWIN_OFFSET))
|
sl@0
|
77 |
|
sl@0
|
78 |
class TIoApic
|
sl@0
|
79 |
{
|
sl@0
|
80 |
public:
|
sl@0
|
81 |
TIoApic(TLinAddr aAddr);
|
sl@0
|
82 |
TUint32 Id();
|
sl@0
|
83 |
TUint32 Ver();
|
sl@0
|
84 |
TUint32 Arb();
|
sl@0
|
85 |
TUint32 Dest(TInt aIndex);
|
sl@0
|
86 |
TUint32 Control(TInt aIndex);
|
sl@0
|
87 |
TUint32 ModifyDest(TInt aIndex, TUint32 aNewDest);
|
sl@0
|
88 |
TUint32 ModifyControl(TInt aIndex, TUint32 aClear, TUint32 aSet);
|
sl@0
|
89 |
|
sl@0
|
90 |
void Dump();
|
sl@0
|
91 |
public:
|
sl@0
|
92 |
TSpinLock iLock;
|
sl@0
|
93 |
TLinAddr iAddr;
|
sl@0
|
94 |
};
|
sl@0
|
95 |
|
sl@0
|
96 |
TIoApic TheIoApic(IO_APIC_BASE);
|
sl@0
|
97 |
|
sl@0
|
98 |
TIoApic::TIoApic(TLinAddr aAddr)
|
sl@0
|
99 |
: iLock(TSpinLock::EOrderBTrace)
|
sl@0
|
100 |
{
|
sl@0
|
101 |
iAddr = aAddr;
|
sl@0
|
102 |
}
|
sl@0
|
103 |
|
sl@0
|
104 |
TUint32 TIoApic::Id()
|
sl@0
|
105 |
{
|
sl@0
|
106 |
TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
|
sl@0
|
107 |
IO_APIC_SELECT(IO_APIC_REG_ID);
|
sl@0
|
108 |
TUint32 x = IO_APIC_REG;
|
sl@0
|
109 |
__SPIN_UNLOCK_IRQRESTORE(iLock,irq);
|
sl@0
|
110 |
return x;
|
sl@0
|
111 |
}
|
sl@0
|
112 |
|
sl@0
|
113 |
TUint32 TIoApic::Ver()
|
sl@0
|
114 |
{
|
sl@0
|
115 |
TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
|
sl@0
|
116 |
IO_APIC_SELECT(IO_APIC_REG_VER);
|
sl@0
|
117 |
TUint32 x = IO_APIC_REG;
|
sl@0
|
118 |
__SPIN_UNLOCK_IRQRESTORE(iLock,irq);
|
sl@0
|
119 |
return x;
|
sl@0
|
120 |
}
|
sl@0
|
121 |
|
sl@0
|
122 |
TUint32 TIoApic::Arb()
|
sl@0
|
123 |
{
|
sl@0
|
124 |
TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
|
sl@0
|
125 |
IO_APIC_SELECT(IO_APIC_REG_ARB);
|
sl@0
|
126 |
TUint32 x = IO_APIC_REG;
|
sl@0
|
127 |
__SPIN_UNLOCK_IRQRESTORE(iLock,irq);
|
sl@0
|
128 |
return x;
|
sl@0
|
129 |
}
|
sl@0
|
130 |
|
sl@0
|
131 |
TUint32 TIoApic::Dest(TInt aIndex)
|
sl@0
|
132 |
{
|
sl@0
|
133 |
TUint32 reg = 2*aIndex + 0x11;
|
sl@0
|
134 |
TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
|
sl@0
|
135 |
IO_APIC_SELECT(reg);
|
sl@0
|
136 |
TUint32 x = IO_APIC_REG;
|
sl@0
|
137 |
__SPIN_UNLOCK_IRQRESTORE(iLock,irq);
|
sl@0
|
138 |
return x>>24;
|
sl@0
|
139 |
}
|
sl@0
|
140 |
|
sl@0
|
141 |
TUint32 TIoApic::Control(TInt aIndex)
|
sl@0
|
142 |
{
|
sl@0
|
143 |
TUint32 reg = 2*aIndex + 0x10;
|
sl@0
|
144 |
TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
|
sl@0
|
145 |
IO_APIC_SELECT(reg);
|
sl@0
|
146 |
TUint32 x = IO_APIC_REG;
|
sl@0
|
147 |
__SPIN_UNLOCK_IRQRESTORE(iLock,irq);
|
sl@0
|
148 |
return x;
|
sl@0
|
149 |
}
|
sl@0
|
150 |
|
sl@0
|
151 |
TUint32 TIoApic::ModifyDest(TInt aIndex, TUint32 aNewDest)
|
sl@0
|
152 |
{
|
sl@0
|
153 |
TUint32 reg = 2*aIndex + 0x11;
|
sl@0
|
154 |
TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
|
sl@0
|
155 |
IO_APIC_SELECT(reg);
|
sl@0
|
156 |
TUint32 x = IO_APIC_REG;
|
sl@0
|
157 |
IO_APIC_REG = (x&0x00ffffffu) | (aNewDest<<24);
|
sl@0
|
158 |
__SPIN_UNLOCK_IRQRESTORE(iLock,irq);
|
sl@0
|
159 |
return x>>24;
|
sl@0
|
160 |
}
|
sl@0
|
161 |
|
sl@0
|
162 |
TUint32 TIoApic::ModifyControl(TInt aIndex, TUint32 aClear, TUint32 aSet)
|
sl@0
|
163 |
{
|
sl@0
|
164 |
TUint32 reg = 2*aIndex + 0x10;
|
sl@0
|
165 |
TInt irq = __SPIN_LOCK_IRQSAVE(iLock);
|
sl@0
|
166 |
IO_APIC_SELECT(reg);
|
sl@0
|
167 |
TUint32 x = IO_APIC_REG;
|
sl@0
|
168 |
x &= ~aClear;
|
sl@0
|
169 |
x |= aSet;
|
sl@0
|
170 |
IO_APIC_SELECT(reg);
|
sl@0
|
171 |
IO_APIC_REG = x;
|
sl@0
|
172 |
__SPIN_UNLOCK_IRQRESTORE(iLock,irq);
|
sl@0
|
173 |
return x;
|
sl@0
|
174 |
}
|
sl@0
|
175 |
|
sl@0
|
176 |
void TIoApic::Dump()
|
sl@0
|
177 |
{
|
sl@0
|
178 |
TUint32 id = Id();
|
sl@0
|
179 |
TUint32 ver = Ver();
|
sl@0
|
180 |
TUint32 arb = Arb();
|
sl@0
|
181 |
__KTRACE_OPT(KBOOT,DEBUGPRINT("IOAPIC ID=%08x VER=%08x ARB=%08x", id, ver, arb));
|
sl@0
|
182 |
|
sl@0
|
183 |
TInt max = (ver>>16)&0xff;
|
sl@0
|
184 |
TInt i;
|
sl@0
|
185 |
for (i=0; i<=max; ++i)
|
sl@0
|
186 |
{
|
sl@0
|
187 |
TUint32 dest = Dest(i);
|
sl@0
|
188 |
TUint32 ctrl = Control(i);
|
sl@0
|
189 |
__KTRACE_OPT(KBOOT,DEBUGPRINT("IOAPIC[%02x] DEST=%02x CTRL=%08x", i, dest, ctrl));
|
sl@0
|
190 |
}
|
sl@0
|
191 |
}
|
sl@0
|
192 |
|
sl@0
|
193 |
|
sl@0
|
194 |
void NIrq::HwEoi()
|
sl@0
|
195 |
{
|
sl@0
|
196 |
if (iX && iX->iEoiFn)
|
sl@0
|
197 |
(*iX->iEoiFn)(this);
|
sl@0
|
198 |
else
|
sl@0
|
199 |
{
|
sl@0
|
200 |
volatile TUint32* const apic_eoi = (volatile TUint32*)(X86_LOCAL_APIC_BASE + X86_LOCAL_APIC_OFFSET_EOI);
|
sl@0
|
201 |
*apic_eoi = 0;
|
sl@0
|
202 |
}
|
sl@0
|
203 |
}
|
sl@0
|
204 |
|
sl@0
|
205 |
void NIrq::HwEnable()
|
sl@0
|
206 |
{
|
sl@0
|
207 |
if (iX && iX->iEnableFn)
|
sl@0
|
208 |
(*iX->iEnableFn)(this);
|
sl@0
|
209 |
else
|
sl@0
|
210 |
{
|
sl@0
|
211 |
// if ((iStaticFlags & ELevel) || (iIState & ERaw))
|
sl@0
|
212 |
TheIoApic.ModifyControl(iIndex, IO_APIC_CTRL_IMASK, 0);
|
sl@0
|
213 |
}
|
sl@0
|
214 |
}
|
sl@0
|
215 |
|
sl@0
|
216 |
void NIrq::HwDisable()
|
sl@0
|
217 |
{
|
sl@0
|
218 |
if (iX && iX->iDisableFn)
|
sl@0
|
219 |
(*iX->iDisableFn)(this);
|
sl@0
|
220 |
else
|
sl@0
|
221 |
{
|
sl@0
|
222 |
if ((iStaticFlags & ELevel) || (iIState & ERaw))
|
sl@0
|
223 |
TheIoApic.ModifyControl(iIndex, 0, IO_APIC_CTRL_IMASK);
|
sl@0
|
224 |
}
|
sl@0
|
225 |
}
|
sl@0
|
226 |
|
sl@0
|
227 |
void NIrq::HwSetCpu(TInt aCpu)
|
sl@0
|
228 |
{
|
sl@0
|
229 |
if (iX && iX->iSetCpuFn)
|
sl@0
|
230 |
(*iX->iSetCpuFn)(this, 1u<<aCpu);
|
sl@0
|
231 |
else
|
sl@0
|
232 |
{
|
sl@0
|
233 |
TheIoApic.ModifyDest(iIndex, 1u<<aCpu);
|
sl@0
|
234 |
}
|
sl@0
|
235 |
}
|
sl@0
|
236 |
|
sl@0
|
237 |
void NIrq::HwSetCpuMask(TUint32 aMask)
|
sl@0
|
238 |
{
|
sl@0
|
239 |
if (iX && iX->iSetCpuFn)
|
sl@0
|
240 |
(*iX->iSetCpuFn)(this, aMask);
|
sl@0
|
241 |
else
|
sl@0
|
242 |
{
|
sl@0
|
243 |
TheIoApic.ModifyDest(iIndex, aMask);
|
sl@0
|
244 |
}
|
sl@0
|
245 |
}
|
sl@0
|
246 |
|
sl@0
|
247 |
void NIrq::HwInit()
|
sl@0
|
248 |
{
|
sl@0
|
249 |
if (iX && iX->iInitFn)
|
sl@0
|
250 |
(*iX->iInitFn)(this);
|
sl@0
|
251 |
else
|
sl@0
|
252 |
{
|
sl@0
|
253 |
__KTRACE_OPT(KBOOT,DEBUGPRINT("NIrq %02x HwInit", iIndex));
|
sl@0
|
254 |
TUint32 clear = IO_APIC_CTRL_INTVEC_MASK;
|
sl@0
|
255 |
TUint32 set = iVector & IO_APIC_CTRL_INTVEC_MASK;
|
sl@0
|
256 |
set |= IO_APIC_CTRL_IMASK;
|
sl@0
|
257 |
if (iStaticFlags & ELevel)
|
sl@0
|
258 |
set |= (IO_APIC_CTRL_LEVEL /*| IO_APIC_CTRL_IMASK*/);
|
sl@0
|
259 |
else
|
sl@0
|
260 |
clear |= (IO_APIC_CTRL_LEVEL /*| IO_APIC_CTRL_IMASK*/);
|
sl@0
|
261 |
if (iStaticFlags & EPolarity)
|
sl@0
|
262 |
clear |= IO_APIC_CTRL_INTPOL_LOW;
|
sl@0
|
263 |
else
|
sl@0
|
264 |
set |= IO_APIC_CTRL_INTPOL_LOW;
|
sl@0
|
265 |
TheIoApic.ModifyControl(iIndex, clear, set);
|
sl@0
|
266 |
TheIoApic.Dump();
|
sl@0
|
267 |
}
|
sl@0
|
268 |
}
|
sl@0
|
269 |
|
sl@0
|
270 |
TBool NIrq::HwPending()
|
sl@0
|
271 |
{
|
sl@0
|
272 |
if (iX && iX->iPendingFn)
|
sl@0
|
273 |
return (*iX->iPendingFn)(this);
|
sl@0
|
274 |
return FALSE;
|
sl@0
|
275 |
}
|
sl@0
|
276 |
|
sl@0
|
277 |
void NIrq::HwWaitCpus()
|
sl@0
|
278 |
{
|
sl@0
|
279 |
if (iX && iX->iWaitFn)
|
sl@0
|
280 |
(*iX->iWaitFn)(this);
|
sl@0
|
281 |
}
|
sl@0
|
282 |
|
sl@0
|
283 |
void NIrq::HwInit0()
|
sl@0
|
284 |
{
|
sl@0
|
285 |
TheIoApic.Dump();
|
sl@0
|
286 |
TInt n = 1 + (TheIoApic.Ver() >> 16);
|
sl@0
|
287 |
TInt i;
|
sl@0
|
288 |
for (i=0; i<n; ++i)
|
sl@0
|
289 |
{
|
sl@0
|
290 |
TheIoApic.ModifyControl(i,
|
sl@0
|
291 |
IO_APIC_CTRL_DELMOD_MASK | IO_APIC_CTRL_INTVEC_MASK | IO_APIC_CTRL_LEVEL | IO_APIC_CTRL_INTPOL_LOW,
|
sl@0
|
292 |
IO_APIC_CTRL_DESTMOD | IO_APIC_CTRL_IMASK | 0xff);
|
sl@0
|
293 |
TheIoApic.ModifyDest(i, 0x01);
|
sl@0
|
294 |
if (i>15)
|
sl@0
|
295 |
{
|
sl@0
|
296 |
TheIoApic.ModifyControl(i, 0, IO_APIC_CTRL_LEVEL | IO_APIC_CTRL_INTPOL_LOW);
|
sl@0
|
297 |
}
|
sl@0
|
298 |
}
|
sl@0
|
299 |
TheIoApic.Dump();
|
sl@0
|
300 |
}
|
sl@0
|
301 |
|
sl@0
|
302 |
void NIrq::HwInit1()
|
sl@0
|
303 |
{
|
sl@0
|
304 |
write_apic_reg(SIVR, 0x300 | SPURIOUS_INTERRUPT_VECTOR);
|
sl@0
|
305 |
write_apic_reg(DIVCNF, 10); // APIC timer clock divide by 128 (bus clock freq / 128)
|
sl@0
|
306 |
write_apic_reg(LVTTMR, 0x10000|TIMESLICE_VECTOR);
|
sl@0
|
307 |
write_apic_reg(DFR, 0xf0000000u); // set flat logical destination mode
|
sl@0
|
308 |
write_apic_reg(LDR, 0x01000000u); // this CPU will be selected by logical destination with bit 0 set
|
sl@0
|
309 |
}
|
sl@0
|
310 |
|
sl@0
|
311 |
void NIrq::HwInit2AP()
|
sl@0
|
312 |
{
|
sl@0
|
313 |
TInt cpu = NKern::CurrentCpu();
|
sl@0
|
314 |
write_apic_reg(SIVR, 0x300 | SPURIOUS_INTERRUPT_VECTOR);
|
sl@0
|
315 |
write_apic_reg(DIVCNF, 10);
|
sl@0
|
316 |
write_apic_reg(LVTTMR, 0x10000|TIMESLICE_VECTOR);
|
sl@0
|
317 |
write_apic_reg(DFR, 0xf0000000u); // set flat logical destination mode
|
sl@0
|
318 |
write_apic_reg(LDR, 0x01000000u<<cpu); // this CPU will be selected by logical destination with bit n set
|
sl@0
|
319 |
}
|