]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/irq_chip.cpp
6c6b0bfff093df99f1b543464413980c48b42065
[l4.git] / kernel / fiasco / src / kern / irq_chip.cpp
1 INTERFACE:
2
3 #include "types.h"
4
5 class Irq_base;
6 class Irq_chip;
7
8 class Upstream_irq
9 {
10 private:
11   Irq_chip *const _c;
12   Mword const _p;
13   Upstream_irq const *const _prev;
14
15 };
16
17 /**
18  * Abstraction for an IRQ controller chip.
19  */
20 class Irq_chip
21 {
22 public:
23   virtual void mask(Mword pin) = 0;
24   virtual void unmask(Mword pin) = 0;
25   virtual void ack(Mword pin) = 0;
26   virtual void mask_and_ack(Mword pin) = 0;
27
28   /**
29    * Set the trigger mode and polarity.
30    */
31   virtual unsigned set_mode(Mword pin, unsigned) = 0;
32
33   /**
34    * Set the target CPU.
35    * \param pin the pin to configure
36    * \param cpu the logical CPU number.
37    */
38   virtual void set_cpu(Mword pin, Cpu_number cpu) = 0;
39   virtual void unbind(Irq_base *irq);
40   virtual ~Irq_chip() = 0;
41 };
42
43 /**
44  * Artificial IRQ chip, used for SW IRQs.
45  */
46 class Irq_chip_soft : public Irq_chip
47 {
48 public:
49   void mask(Mword) {}
50   void unmask(Mword) {}
51   void mask_and_ack(Mword) {}
52   void ack(Mword) {}
53
54   void set_cpu(Mword, Cpu_number) {}
55   unsigned set_mode(Mword, unsigned mode) { return mode; }
56
57   char const *chip_type() const { return "Soft"; }
58
59   static Irq_chip_soft sw_chip;
60 };
61
62 /**
63  * Abstract IRQ controller chip that is visble as part of the
64  * Icu to the user.
65  */
66 class Irq_chip_icu : public Irq_chip
67 {
68 public:
69   virtual bool reserve(Mword pin) = 0;
70   virtual bool alloc(Irq_base *irq, Mword pin) = 0;
71   virtual Irq_base *irq(Mword pin) const = 0;
72   virtual unsigned nr_irqs() const = 0;
73   virtual ~Irq_chip_icu() = 0;
74 };
75
76
77 class Kobject_iface;
78
79
80 /**
81  * Base class for all kinds of IRQ consuming objects.
82  */
83 class Irq_base
84 {
85   friend class Irq_chip;
86
87 public:
88
89   typedef void (*Hit_func)(Irq_base *, Upstream_irq const *);
90   enum Flags
91   {
92     F_enabled = 1,
93   };
94
95   enum Mode
96   {
97     Set_irq_mode  = 0x1,
98     Trigger_edge  = 0x0,
99     Trigger_level = 0x2,
100     Trigger_mask  = 0x2,
101
102     Polarity_high = 0x0,
103     Polarity_low  = 0x4,
104     Polarity_both = 0x8,
105     Polarity_mask = 0xc,
106   };
107
108   Irq_base() : _flags(Trigger_level), _next(0)
109   {
110     Irq_chip_soft::sw_chip.bind(this, 0, true);
111     mask();
112   }
113
114   void hit(Upstream_irq const *ui) { hit_func(this, ui); }
115
116   Mword pin() const { return _pin; }
117   Irq_chip *chip() const { return _chip; }
118
119   void mask() { if (!__mask()) _chip->mask(_pin); }
120   void mask_and_ack()
121   {
122     if (!__mask())
123       _chip->mask_and_ack(_pin);
124     else
125       _chip->ack(_pin);
126   }
127
128   void unmask() { if (__unmask()) _chip->unmask(_pin); }
129   void ack() { _chip->ack(_pin); }
130
131
132   void set_mode(unsigned m)
133   {
134     unsigned mode = _chip->set_mode(_pin, m);
135     _flags = (_flags & ~0xe) | (mode & 0xe);
136     switch_mode(mode);
137   }
138
139   void set_cpu(Cpu_number cpu) { _chip->set_cpu(_pin, cpu); }
140
141   unsigned get_mode() const
142   { return _flags & 0xe; }
143
144   bool masked() const { return !(_flags & F_enabled); }
145   Mword flags() const { return _flags; }
146
147   void unbind() { _chip->unbind(this); }
148
149   bool __mask() { bool o = masked(); _flags &= ~F_enabled; return o; }
150   bool __unmask() { bool o = masked(); _flags |= F_enabled; return o; }
151
152   void set_hit(Hit_func f) { hit_func = f; }
153   virtual void switch_mode(unsigned mode) = 0;
154   virtual ~Irq_base() = 0;
155
156 protected:
157   Hit_func hit_func;
158
159   Irq_chip *_chip;
160   Mword _pin;
161   unsigned _flags;
162
163   template<typename T>
164   static void handler_wrapper(Irq_base *irq, Upstream_irq const *ui)
165   { nonull_static_cast<T*>(irq)->handle(ui); }
166
167 public:
168   Irq_base *_next;
169
170   static Irq_base *(*dcast)(Kobject_iface *);
171 };
172
173
174
175
176 //----------------------------------------------------------------------------
177 INTERFACE [debug]:
178
179 EXTENSION class Irq_chip
180 {
181 public:
182   virtual char const *chip_type() const = 0;
183 };
184
185
186 //--------------------------------------------------------------------------
187 IMPLEMENTATION:
188
189 #include "types.h"
190 #include "cpu_lock.h"
191 #include "lock_guard.h"
192 #include "static_init.h"
193
194 Irq_chip_soft Irq_chip_soft::sw_chip INIT_PRIORITY(EARLY_INIT_PRIO);
195 Irq_base *(*Irq_base::dcast)(Kobject_iface *);
196
197 IMPLEMENT inline Irq_chip::~Irq_chip() {}
198 IMPLEMENT inline Irq_chip_icu::~Irq_chip_icu() {}
199 IMPLEMENT inline Irq_base::~Irq_base() {}
200
201 PUBLIC inline explicit
202 Upstream_irq::Upstream_irq(Irq_base const *b, Upstream_irq const *prev)
203 : _c(b->chip()), _p(b->pin()), _prev(prev)
204 {}
205
206 PUBLIC inline
207 void
208 Upstream_irq::ack() const
209 {
210   for (Upstream_irq const *c = this; c; c = c->_prev)
211     c->_c->ack(c->_p);
212 }
213
214
215 PUBLIC inline
216 void
217 Irq_chip::bind(Irq_base *irq, Mword pin, bool ctor = false)
218 {
219   irq->_pin = pin;
220   irq->_chip = this;
221
222   if (ctor)
223     return;
224
225   irq->set_mode(irq->get_mode());
226   if (irq->masked())
227     mask(pin);
228   else
229     unmask(pin);
230 }
231
232 IMPLEMENT inline
233 void
234 Irq_chip::unbind(Irq_base *irq)
235 {
236   Irq_chip_soft::sw_chip.bind(irq, 0, true);
237 }
238
239
240 /**
241  * \param CHIP must be the dynamic type of the object.
242  */
243 PUBLIC inline
244 template<typename CHIP>
245 void
246 Irq_chip::handle_irq(Mword pin, Upstream_irq const *ui)
247 {
248   // call the irq function of the chip avoiding the
249   // virtual function call overhead.
250   Irq_base *irq = nonull_static_cast<CHIP*>(this)->CHIP::irq(pin);
251   irq->log();
252   irq->hit(ui);
253 }
254
255 PUBLIC inline
256 template<typename CHIP>
257 void
258 Irq_chip::handle_multi_pending(Upstream_irq const *ui)
259 {
260   while (Mword pend = nonull_static_cast<CHIP*>(this)->CHIP::pending())
261     {
262       for (unsigned i = 0; i < sizeof(Mword)*8; ++i, pend >>= 1)
263         if (pend & 1)
264           {
265             handle_irq<CHIP>(i, ui);
266             break; // read the pending ints again
267           }
268     }
269 }
270
271
272 PUBLIC inline NEEDS["lock_guard.h", "cpu_lock.h"]
273 void
274 Irq_base::destroy()
275 {
276   auto g = lock_guard(cpu_lock);
277   unbind();
278 }
279
280
281 // --------------------------------------------------------------------------
282 IMPLEMENTATION [!debug]:
283
284 PUBLIC inline void Irq_base::log() {}
285
286 //-----------------------------------------------------------------------------
287 INTERFACE [debug]:
288
289 #include "tb_entry.h"
290
291 EXTENSION class Irq_base
292 {
293 public:
294   struct Irq_log : public Tb_entry
295   {
296     Irq_base *obj;
297     Irq_chip *chip;
298     Mword pin;
299     unsigned print(int max, char *buf) const;
300   };
301 };
302
303
304 // --------------------------------------------------------------------------
305 IMPLEMENTATION [debug]:
306
307 #include <cstdio>
308
309 #include "logdefs.h"
310 #include "kobject_dbg.h"
311
312 IMPLEMENT
313 unsigned
314 Irq_base::Irq_log::print(int maxlen, char *buf) const
315 {
316   Kobject_dbg::Const_iterator irq = Kobject_dbg::pointer_to_obj(obj);
317
318   if (irq != Kobject_dbg::end())
319     return snprintf(buf, maxlen, "0x%lx/%lu @ chip %s(%p) D:%lx",
320                     pin, pin, chip->chip_type(), chip,
321                     irq->dbg_id());
322   else
323     return snprintf(buf, maxlen, "0x%lx/%lu @ chip %s(%p) irq=%p",
324                     pin, pin, chip->chip_type(), chip,
325                     obj);
326 }
327
328 PUBLIC inline NEEDS["logdefs.h"]
329 void
330 Irq_base::log()
331 {
332   Context *c = current();
333   LOG_TRACE("IRQ-Object triggers", "irq", c, Irq_log,
334       l->obj = this;
335       l->chip = chip();
336       l->pin = pin();
337   );
338 }
339