]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/irq_mgr_flex.cpp
Some minor fixes.
[l4.git] / kernel / fiasco / src / kern / irq_mgr_flex.cpp
1 INTERFACE:
2
3 #include "irq_mgr.h"
4 #include <cstdio>
5
6 /**
7  * Flexible IRQ manager (manages multiple IRQ chips).
8  *
9  * This manager allow to manage up to `MAX_CHIPS` IRQ chips, where each chip
10  * gets a contiguous range of externally visible (global IRQ numbers)
11  * assigned.  The ranges of the different chips must not overlap. However each
12  * chip can start at an arbitrary 16bit IRQ number.
13  */
14 template<unsigned MAX_CHIPS>
15 class Irq_mgr_flex : public Irq_mgr
16 {
17 public:
18   unsigned max_chips() const { return MAX_CHIPS; }
19
20   unsigned nr_irqs() const override
21   { return _max_irq; }
22
23   unsigned nr_msis() const override
24   { return 0; }
25
26   Irq chip(Mword irqnum) const override
27   {
28     for (unsigned i = 0; i < _used; ++i)
29       if (irqnum < _chips[i].end)
30         return Irq(_chips[i].chip, irqnum - _chips[i].start);
31
32     return Irq();
33   }
34
35   /**
36    * Add a chip starting its range at `pos`.
37    * \param chip  The chip to add.
38    * \param pos   The first global IRQ number assigned to pin 0 of `chip`.
39    *              use `-1` to assign the next free global IRQ number.
40    *
41    * This function checks for overlaps and returns an error string in case
42    * of any conflicts.
43    */
44   char const *add_chip(Irq_chip_icu *chip, int pos = -1)
45   {
46     if (_used >= MAX_CHIPS)
47       return "too many IRQ chips";
48
49     unsigned n = chip->nr_irqs();
50     if (n == 0)
51       return "chip with zero interrupts";
52
53     if (pos < 0)
54       pos = _max_irq;
55
56     if (pos >= (int)_max_irq)
57       {
58         // add as last
59         auto &e = _chips[_used++];
60         e.start = pos;
61         _max_irq = pos + n;
62         e.end   = _max_irq;
63         e.chip  = chip;
64         return 0;
65       }
66
67     Chip *spot = 0;
68     for (unsigned x = 0; x < _used; ++x)
69       {
70         spot = &_chips[x];
71
72         if (pos >= spot->end)
73           continue;
74
75         if (pos + n >= spot->start)
76           return "overlapping interrupt ranges";
77       }
78
79     for (Chip *x = &_chips[_used]; x >= spot; --x)
80       x[1] = x[0];
81
82     ++_used;
83
84     spot->start = pos;
85     spot->end   = pos + n;
86     spot->chip = chip;
87
88     if (pos + n > _max_irq)
89       _max_irq = pos + n;
90
91     return 0;
92   }
93
94 private:
95   struct Chip
96   {
97     unsigned short start;
98     unsigned short end;
99     Irq_chip_icu *chip;
100   };
101   unsigned _used = 0;
102   unsigned _max_irq = 0;
103   Chip _chips[MAX_CHIPS];
104 };
105
106 IMPLEMENTATION [!debug]:
107
108 PUBLIC template<unsigned MAX_CHIPS>
109 void
110 Irq_mgr_flex<MAX_CHIPS>::print_infos()
111 {
112   for (auto *e = _chips; e != _chips + _used; ++e)
113     printf("  %3d-%3d: @%p\n", e->start, e->end - 1, e->chip);
114 }
115 IMPLEMENTATION [debug]:
116
117 PUBLIC template<unsigned MAX_CHIPS>
118 void
119 Irq_mgr_flex<MAX_CHIPS>::print_infos()
120 {
121   for (auto *e = _chips; e != _chips + _used; ++e)
122     printf("  %3d-%3d: %s\n", e->start, e->end - 1, e->chip->chip_type());
123 }
124