]> 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);
153   Idt::set_entry(vector, Address(&entry_int_apic_ignore), false);
154 }
155
156 PUBLIC void
157 Pin_io_apic_edge::do_mask_and_ack()
158 {
159   assert (cpu_lock.test());
160   Apic::irq_ack();
161 }
162
163
164 PUBLIC void
165 Pin_io_apic_edge::do_set_mode(unsigned mode)
166 {
167   Io_apic_entry e = apic()->read_entry(irq());
168   e.polarity(to_io_apic_polarity(mode));
169   e.trigger(to_io_apic_trigger(mode));
170   apic()->write_entry(irq(), e);
171   if (mode & Irq::Trigger_level)
172     new (this) Pin_io_apic_level(apic_idx(), irq());
173 }
174
175
176 PUBLIC void
177 Pin_io_apic_level::do_mask()
178 {
179   assert (cpu_lock.test());
180   apic()->mask(irq());
181   apic()->sync();
182 }
183
184
185 PUBLIC
186 void
187 Pin_io_apic_level::ack()
188 {
189   assert (cpu_lock.test());
190   Apic::irq_ack();
191 }
192
193
194
195 PUBLIC void
196 Pin_io_apic_level::do_mask_and_ack()
197 {
198   assert (cpu_lock.test());
199   __mask();
200   apic()->mask(irq());
201   apic()->sync();
202   Apic::irq_ack();
203 }
204
205
206 PUBLIC void
207 Pin_io_apic_level::do_unmask()
208 {
209   assert (cpu_lock.test());
210   apic()->unmask(irq());
211 }
212
213 PUBLIC void
214 Pin_io_apic_level::set_cpu(unsigned cpu)
215 {
216   apic()->set_dest(irq(), Cpu::cpus.cpu(cpu).phys_id());
217 }
218
219
220 PUBLIC void
221 Pin_io_apic_level::do_set_mode(unsigned mode)
222 {
223   Io_apic_entry e = apic()->read_entry(irq());
224   e.polarity(to_io_apic_polarity(mode));
225   e.trigger(to_io_apic_trigger(mode));
226   apic()->write_entry(irq(), e);
227   if (!(mode & Irq::Trigger_level))
228     new (this) Pin_io_apic_edge(apic_idx(), irq());
229 }
230
231
232 PUBLIC static FIASCO_INIT
233 void
234 Dirq_io_apic::init()
235 {
236   static Chip _ia;
237   Irq_chip::hw_chip = &_ia;
238 }
239
240 // --------------------------------------------------------------------------
241 IMPLEMENTATION [debug]:
242
243 PUBLIC
244 char const *
245 Pin_io_apic_level::pin_type() const
246 { return "HW IRQ (IOAPIC level)"; }
247
248 PUBLIC
249 char const *
250 Pin_io_apic_edge::pin_type() const
251 { return "HW IRQ (IOAPIC edge)"; }