]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/dirq_io_apic.cpp
update
[l4.git] / kernel / fiasco / src / kern / dirq_io_apic.cpp
1 INTERFACE:
2
3 #include "dirq_pic_pin.h"
4 #include "initcalls.h"
5
6 class Dirq_io_apic : public Dirq_pic_pin
7 {
8 protected:
9   class Chip : public Dirq_pic_pin::Chip
10   {
11   public:
12     bool alloc(Irq_base *irq, unsigned irqnum);
13     void setup(Irq_base *irq, unsigned irqnum);
14     unsigned legacy_override(unsigned irq);
15     unsigned nr_irqs() const;
16     void disable_irq(unsigned irqnum);
17   };
18 };
19
20
21
22 IMPLEMENTATION:
23
24 #include "apic.h"
25 #include "io_apic.h"
26 #include "receiver.h"
27 #include "idt.h"
28 #include "irq.h"
29 #include "vkey.h"
30
31 enum
32 {
33   Default_mode = Irq::Trigger_edge | Irq::Polarity_high,
34   //Default_mode = Irq::Trigger_level | Irq::Polarity_high,
35 };
36
37
38 IMPLEMENT
39 unsigned
40 Dirq_io_apic::Chip::legacy_override(unsigned irq)
41 {
42   return Io_apic::legacy_override(irq);
43 }
44
45
46
47 IMPLEMENT
48 unsigned
49 Dirq_io_apic::Chip::nr_irqs() const
50 { return Io_apic::total_irqs(); }
51
52
53 IMPLEMENT
54 void
55 Dirq_io_apic::Chip::setup(Irq_base *irq, unsigned irqnum)
56 {
57   unsigned apic_idx = Io_apic::find_apic(irqnum);
58   irqnum -= Io_apic::apic(apic_idx)->gsi_offset();
59
60   //irq->pin()->set_mode(Default_mode);
61   if (irq->pin()->get_mode() & Irq::Trigger_level)
62     irq->pin()->replace<Pin_io_apic_level>(apic_idx, irqnum);
63   else
64     irq->pin()->replace<Pin_io_apic_edge>(apic_idx, irqnum);
65 }
66
67 IMPLEMENT
68 bool
69 Dirq_io_apic::Chip::alloc(Irq_base *irq, unsigned irqnum)
70 {
71   if (!Dirq_pic_pin::Chip::alloc(irq, irqnum))
72     return false;
73
74
75   unsigned apic_idx = Io_apic::find_apic(irqnum);
76   Io_apic *a = Io_apic::apic(apic_idx);
77   unsigned lirqn = irqnum - a->gsi_offset();
78
79
80   Io_apic_entry e = a->read_entry(lirqn);
81   e.vector(vector(irqnum));
82   a->write_entry(lirqn, e);
83   return true;
84 }
85
86 IMPLEMENT
87 void
88 Dirq_io_apic::Chip::disable_irq(unsigned vector)
89 {
90   extern char entry_int_apic_ignore[];
91   Idt::set_entry(vector, Address(&entry_int_apic_ignore), false);
92 }
93
94 static inline
95 Mword to_io_apic_trigger(unsigned mode)
96 {
97   return (mode & Irq::Trigger_level)
98             ? Io_apic_entry::Level
99             : Io_apic_entry::Edge;
100 }
101
102 static inline
103 Mword to_io_apic_polarity(unsigned mode)
104 {
105   return (mode & Irq::Polarity_low)
106              ? Io_apic_entry::Low_active
107              : Io_apic_entry::High_active;
108 }
109
110 class Pin_io_apic_level : public Irq_pin
111 {
112 public:
113   explicit Pin_io_apic_level(unsigned apic, unsigned irq)
114   { payload()[0] = apic + (irq << 16); }
115
116   unsigned irq() const { return payload()[0] >> 16; }
117   unsigned apic_idx() const { return payload()[0] & 0xffff; }
118   Io_apic *apic() const { return Io_apic::apic(apic_idx()); }
119   unsigned gsi() const { return apic()->gsi_offset() + irq(); }
120 };
121
122 class Pin_io_apic_edge : public Pin_io_apic_level
123 {
124 public:
125   explicit Pin_io_apic_edge(unsigned apic, unsigned irq)
126   : Pin_io_apic_level(apic, irq) {}
127 };
128
129 PUBLIC
130 bool
131 Pin_io_apic_level::check_debug_irq()
132 {
133   return !Vkey::check_(gsi());
134 }
135
136 PUBLIC
137 void
138 Pin_io_apic_level::unbind_irq()
139 {
140   do_mask();
141   disable();
142   Irq_chip::hw_chip->free(Irq::self(this), gsi());
143   replace<Sw_irq_pin>();
144 }
145
146 PUBLIC
147 void
148 Pin_io_apic_level::disable()
149 {
150   extern char entry_int_apic_ignore[];
151   unsigned vector = Dirq_pic_pin::Chip::vector(gsi());
152   Dirq_pic_pin::Chip::vfree(Irq_base::self(this), vector, &entry_int_apic_ignore);
153 }
154
155 PUBLIC void
156 Pin_io_apic_edge::do_mask_and_ack()
157 {
158   assert (cpu_lock.test());
159   Apic::irq_ack();
160 }
161
162
163 PUBLIC void
164 Pin_io_apic_edge::do_set_mode(unsigned mode)
165 {
166   Io_apic_entry e = apic()->read_entry(irq());
167   e.polarity(to_io_apic_polarity(mode));
168   e.trigger(to_io_apic_trigger(mode));
169   apic()->write_entry(irq(), e);
170   if (mode & Irq::Trigger_level)
171     new (this) Pin_io_apic_level(apic_idx(), irq());
172 }
173
174
175 PUBLIC void
176 Pin_io_apic_level::do_mask()
177 {
178   assert (cpu_lock.test());
179   apic()->mask(irq());
180   apic()->sync();
181 }
182
183
184 PUBLIC
185 void
186 Pin_io_apic_level::ack()
187 {
188   assert (cpu_lock.test());
189   Apic::irq_ack();
190 }
191
192
193
194 PUBLIC void
195 Pin_io_apic_level::do_mask_and_ack()
196 {
197   assert (cpu_lock.test());
198   __mask();
199   apic()->mask(irq());
200   apic()->sync();
201   Apic::irq_ack();
202 }
203
204
205 PUBLIC void
206 Pin_io_apic_level::do_unmask()
207 {
208   assert (cpu_lock.test());
209   apic()->unmask(irq());
210 }
211
212 PUBLIC void
213 Pin_io_apic_level::set_cpu(unsigned cpu)
214 {
215   apic()->set_dest(irq(), Cpu::cpus.cpu(cpu).phys_id());
216 }
217
218
219 PUBLIC void
220 Pin_io_apic_level::do_set_mode(unsigned mode)
221 {
222   Io_apic_entry e = apic()->read_entry(irq());
223   e.polarity(to_io_apic_polarity(mode));
224   e.trigger(to_io_apic_trigger(mode));
225   apic()->write_entry(irq(), e);
226   if (!(mode & Irq::Trigger_level))
227     new (this) Pin_io_apic_edge(apic_idx(), irq());
228 }
229
230
231 PUBLIC static FIASCO_INIT
232 void
233 Dirq_io_apic::init()
234 {
235   static Chip _ia;
236   Irq_chip::hw_chip = &_ia;
237 }
238
239 // --------------------------------------------------------------------------
240 IMPLEMENTATION [debug]:
241
242 PUBLIC
243 char const *
244 Pin_io_apic_level::pin_type() const
245 { return "HW IRQ (IOAPIC level)"; }
246
247 PUBLIC
248 char const *
249 Pin_io_apic_edge::pin_type() const
250 { return "HW IRQ (IOAPIC edge)"; }