]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/arm/gic.cpp
Inital import
[l4.git] / kernel / fiasco / src / kern / arm / gic.cpp
1 INTERFACE [arm && pic_gic]:
2
3 #include "kmem.h"
4 #include "irq_chip.h"
5 #include "irq_pin.h"
6
7
8 class Gic
9 {
10 private:
11   Address _cpu_base;
12   Address _dist_base;
13
14   enum
15   {
16     DIST_CTRL         = 0x000,
17     DIST_CTR          = 0x004,
18     DIST_IRQ_SEC      = 0x080,
19     DIST_ENABLE_SET   = 0x100,
20     DIST_ENABLE_CLEAR = 0x180,
21     DIST_PRI          = 0x400,
22     DIST_TARGET       = 0x800,
23     DIST_CONFIG       = 0xc00,
24     DIST_SOFTINT      = 0xf00,
25
26     CPU_CTRL          = 0x00,
27     CPU_PRIMASK       = 0x04,
28     CPU_BPR           = 0x08,
29     CPU_INTACK        = 0x0c,
30     CPU_EOI           = 0x10,
31     CPU_RUNINT        = 0x14,
32     CPU_PENDING       = 0x18,
33
34     CPU_CTRL_ENABLE          = 1,
35     CPU_CTRL_USE_FIQ_FOR_SEC = 8,
36   };
37 };
38
39 class Gic_pin : public Irq_pin
40 {
41 public:
42   Gic_pin(unsigned gic_idx, unsigned irq)
43   { payload()[0] = (gic_idx << 16) | irq; }
44
45   unsigned irq() const { return payload()[0] & 0xffff; }
46   Gic *gic() const { return &_gic[payload()[0] >> 16]; }
47
48   static Gic _gic[];
49 };
50
51 class Gic_cascade_pin : public Gic_pin
52 {
53 public:
54   Gic_cascade_pin(unsigned gic_idx, unsigned irq)
55     : Gic_pin(gic_idx, irq) {}
56 };
57
58 class Gic_cascade_irq : public Irq_base
59 {
60 public:
61   explicit Gic_cascade_irq(Gic *child_gic, Unsigned32 irq_offset)
62     : _child_gic(child_gic), _irq_offset(irq_offset) {}
63
64   Unsigned32 irq_offset() const { return _irq_offset; }
65   Gic *child_gic() const { return _child_gic; }
66 private:
67   Gic *_child_gic;
68   Unsigned32 _irq_offset;
69 };
70
71 //-------------------------------------------------------------------
72 IMPLEMENTATION [arm && pic_gic]:
73
74 #include <cstring>
75 #include <cstdio>
76
77 #include "io.h"
78 #include "irq.h"
79 #include "irq_chip_generic.h"
80 #include "panic.h"
81 #include "vkey.h"
82
83 PUBLIC inline NEEDS["io.h"]
84 unsigned
85 Gic::nr_irqs()
86 { return ((Io::read<Mword>(_dist_base + DIST_CTR) & 0x1f) + 1) * 32; }
87
88 PUBLIC inline NEEDS["io.h"]
89 bool
90 Gic::has_sec_ext()
91 { return Io::read<Mword>(_dist_base + DIST_CTR) & (1 << 10); }
92
93 PUBLIC inline
94 void Gic::softint_cpu(unsigned callmap, unsigned m)
95 {
96   Io::write<Mword>((callmap & 0xff) << 16 | m, _dist_base + DIST_SOFTINT);
97 }
98
99 PUBLIC inline
100 void Gic::softint_bcast(unsigned m)
101 { Io::write<Mword>(1 << 24 | m, _dist_base + DIST_SOFTINT); }
102
103 PUBLIC
104 void
105 Gic::init_ap()
106 {
107   Io::write<Mword>(CPU_CTRL_ENABLE, _cpu_base + CPU_CTRL);
108   Io::write<Mword>(0xf0, _cpu_base + CPU_PRIMASK);
109 }
110
111 PUBLIC
112 void
113 Gic::init(Address cpu_base, Address dist_base)
114 {
115   _cpu_base = cpu_base;
116   _dist_base = dist_base;
117
118   Io::write<Mword>(0, _dist_base + DIST_CTRL);
119
120   unsigned num = nr_irqs();
121   printf("Number of IRQs available at this GIC: %d\n", num);
122
123   unsigned int intmask = 1 << Proc::cpu_id();
124   intmask |= intmask << 8;
125   intmask |= intmask << 16;
126
127   for (unsigned i = 32; i < num; i += 16)
128     Io::write<Mword>(0, _dist_base + DIST_CONFIG + i * 4 / 16);
129   for (unsigned i = 32; i < num; i += 4)
130     Io::write<Mword>(intmask, _dist_base + DIST_TARGET + i);
131   for (unsigned i = 0; i < num; i += 4)
132     Io::write<Mword>(0xa0a0a0a0, _dist_base + DIST_PRI + i);
133   for (unsigned i = 0; i < num; i += 32)
134     Io::write<Mword>(0xffffffff, _dist_base + DIST_ENABLE_CLEAR + i * 4 / 32);
135
136   Io::write<Mword>(1, _dist_base + DIST_CTRL);
137
138   Io::write<Mword>(CPU_CTRL_ENABLE, _cpu_base + CPU_CTRL);
139   Io::write<Mword>(0xf0, _cpu_base + CPU_PRIMASK);
140
141   //enable_tz_support();
142 }
143
144 PUBLIC inline NEEDS["io.h"]
145 void Gic::disable_locked( unsigned irq )
146 { Io::write<Mword>(1 << (irq % 32), _dist_base + DIST_ENABLE_CLEAR + (irq / 32) * 4); }
147
148 PUBLIC inline NEEDS["io.h"]
149 void Gic::enable_locked(unsigned irq, unsigned /*prio*/)
150 { Io::write<Mword>(1 << (irq % 32), _dist_base + DIST_ENABLE_SET + (irq / 32) * 4); }
151
152 PUBLIC inline NEEDS [Gic::enable_locked]
153 void Gic::acknowledge_locked( unsigned irq )
154 { Io::write<Mword>(irq, _cpu_base + CPU_EOI); }
155
156 PUBLIC
157 void
158 Gic_pin::unbind_irq()
159 {
160   mask();
161   disable();
162   Irq_chip::hw_chip->free(Irq::self(this), irq());
163   replace<Sw_irq_pin>();
164 }
165
166 PUBLIC
167 void
168 Gic_pin::do_mask()
169 {
170   assert (cpu_lock.test());
171   gic()->disable_locked(irq());
172 }
173
174 PUBLIC
175 void
176 Gic_pin::do_mask_and_ack()
177 {
178   assert (cpu_lock.test());
179   __mask();
180   gic()->disable_locked(irq());
181   gic()->acknowledge_locked(irq());
182 }
183
184 PUBLIC
185 void
186 Gic_pin::ack()
187 {
188   gic()->acknowledge_locked(irq());
189 }
190
191 PUBLIC
192 void
193 Gic_pin::hit()
194 {
195   Irq::self(this)->Irq::hit();
196 }
197
198 PUBLIC
199 void
200 Gic_pin::do_unmask()
201 {
202   assert (cpu_lock.test());
203   gic()->enable_locked(irq(), 0xa);
204 }
205
206 PUBLIC
207 void
208 Gic_pin::do_set_mode(unsigned)
209 {}
210
211 PUBLIC
212 bool
213 Gic_pin::check_debug_irq()
214 {
215   return !Vkey::check_(irq());
216 }
217
218
219 PUBLIC static inline
220 Gic_cascade_irq *
221 Gic_cascade_irq::self(Irq_pin const *pin)
222 {
223 #define MYoffsetof(TYPE, MEMBER) (((size_t) &((TYPE *)10)->MEMBER) - 10)
224   return reinterpret_cast<Gic_cascade_irq*>(reinterpret_cast<Mword>(pin)
225                 - MYoffsetof(Gic_cascade_irq, _pin));
226 #undef MYoffsetof
227
228 }
229
230 PUBLIC
231 void
232 Gic_cascade_pin::hit()
233 {
234   Unsigned32 num = Gic_cascade_irq::self(this)->child_gic()->pending();
235   if (num == 0x3ff)
236     return;
237
238   Irq *i = nonull_static_cast<Irq*>(Irq_chip_gen::lookup(num + Gic_cascade_irq::self(this)->irq_offset()));
239   i->pin()->hit();
240
241   gic()->acknowledge_locked(irq());
242 }
243
244 //-------------------------------------------------------------------
245 IMPLEMENTATION [arm && !mp && pic_gic]:
246
247 PUBLIC
248 void
249 Gic_pin::set_cpu(unsigned)
250 {}
251
252 PUBLIC inline NEEDS["io.h"]
253 Unsigned32 Gic::pending()
254 { return Io::read<Mword>(_cpu_base + CPU_INTACK) & 0x3ff; }
255
256 //-------------------------------------------------------------------
257 IMPLEMENTATION [arm && mp && pic_gic]:
258
259 #include "cpu.h"
260
261 PUBLIC inline NEEDS["io.h"]
262 Unsigned32 Gic::pending()
263 {
264   Unsigned32 ack = Io::read<Mword>(_cpu_base + CPU_INTACK);
265
266   // IPIs/SGIs need to take the whole ack value
267   if ((ack & 0x3ff) < 16)
268     Io::write<Mword>(ack, _cpu_base + CPU_EOI);
269
270   return ack & 0x3ff;
271 }
272
273 PUBLIC inline NEEDS["cpu.h"]
274 void
275 Gic::set_cpu(unsigned irq, unsigned cpu)
276 {
277   Mword reg = _dist_base + DIST_TARGET + (irq & ~3);
278   Mword val = Io::read<Mword>(reg);
279
280   int shift = (irq % 4) * 8;
281   val = (val & ~(0xf << shift)) | (1 << (Cpu::cpus.cpu(cpu).phys_id() + shift));
282
283   Io::write<Mword>(val, reg);
284 }
285
286 PUBLIC
287 void
288 Gic_pin::set_cpu(unsigned cpu)
289 {
290   gic()->set_cpu(irq(), cpu);
291 }
292
293 //-------------------------------------------------------------------
294 IMPLEMENTATION [arm && pic_gic && tz]:
295
296 #if 0
297 PRIVATE
298 void
299 Gic::set_irq_nonsecure(unsigned irqnum)
300 {
301   Io::set<Mword>(1 << (irqnum % 32),
302                  _dist_base + DIST_IRQ_SEC + ((irqnum & ~31) / 8));
303 }
304 #endif
305
306 PUBLIC inline NEEDS[<cstdio>]
307 void
308 Gic::enable_tz_support()
309 {
310   if (has_sec_ext())
311     printf("GIC:Has security extension\n");
312
313   printf("GIC: Signal secure Interrupts as FIQs!\n");
314   Io::write<Mword>(CPU_CTRL_ENABLE | CPU_CTRL_USE_FIQ_FOR_SEC,
315                    _cpu_base + CPU_CTRL);
316 }
317
318 //-------------------------------------------------------------------
319 IMPLEMENTATION [arm && pic_gic && !tz]:
320
321 PUBLIC inline
322 void
323 Gic::enable_tz_support()
324 {}
325
326 //---------------------------------------------------------------------------
327 IMPLEMENTATION [debug]:
328
329 PUBLIC
330 char const *
331 Gic_pin::pin_type() const
332 { return "HW GIC IRQ"; }