]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/io/server/src/vicu.cc
update
[l4.git] / l4 / pkg / io / server / src / vicu.cc
1 /*
2  * (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
3  *     economic rights: Technische Universität Dresden (Germany)
4  *
5  * This file is part of TUD:OS and distributed under the terms of the
6  * GNU General Public License 2.
7  * Please see the COPYING-GPL-2 file for details.
8  */
9
10 #include <l4/vbus/vdevice-ops.h>
11
12 #include "vicu.h"
13 #include "vbus_factory.h"
14 #include "server.h"
15 #include "main.h"
16 #include "debug.h"
17
18 #include <l4/re/util/cap_alloc>
19 #include <l4/re/namespace>
20 #include <l4/re/env>
21 #include <l4/re/error_helper>
22 #include <l4/sys/icu>
23 #include <l4/sys/irq>
24 #include <l4/sys/debugger.h>
25 #include <l4/sys/kdebug.h>
26
27 #include <cassert>
28 #include <pthread.h>
29 #include <pthread-l4.h>
30
31 namespace Vi {
32
33 using L4Re::Util::Auto_cap;
34 using L4Re::chksys;
35 using L4Re::chkcap;
36
37 enum { MAX_HW_IRQS = 256 };
38
39 Kernel_irq_pin *Sw_icu::_real_irqs[MAX_HW_IRQS];
40
41 Kernel_irq_pin *
42 Sw_icu::real_irq(unsigned n)
43 {
44   if (n >= sizeof(_real_irqs)/sizeof(_real_irqs[0]))
45     return 0;
46
47   if (!_real_irqs[n])
48     _real_irqs[n] = new Kernel_irq_pin(n);
49
50   return _real_irqs[n];
51 }
52
53
54 Sw_icu::Sw_icu()
55 {
56   add_feature(this);
57   registry->register_obj(this);
58 }
59
60 Sw_icu::~Sw_icu()
61 {
62   registry->unregister_obj(this);
63 }
64
65 int
66 Sw_icu::bind_irq(l4_msgtag_t tag, unsigned irqn, L4::Snd_fpage const &/*irqc*/)
67 {
68   if (tag.items() < 1)
69     return -L4_EINVAL;
70
71   d_printf(DBG_ALL, "%s[%p]: bind_irq(%d, ...)\n", name(), this, irqn);
72
73   Irq_set::Iterator i = _irqs.find(irqn);
74   if (i == _irqs.end())
75     return -L4_ENOENT;
76
77   int err = i->bind(rcv_cap);
78   if (err < 0)
79     d_printf(DBG_ERR, "ERROR: binding irq %d, result is %d (%s)\n", irqn, err, l4sys_errtostr(err));
80
81   return err;
82 }
83
84 int
85 Sw_icu::unbind_irq(l4_msgtag_t tag, unsigned irqn, L4::Snd_fpage const &/*irqc*/)
86 {
87   if (tag.items() < 1)
88     return -L4_EINVAL;
89
90   d_printf(DBG_ALL, "%s[%p]: unbind_irq(%d, ...)\n", name(), this, irqn);
91
92   Irq_set::Iterator i = _irqs.find(irqn);
93   if (i == _irqs.end())
94     return -L4_ENOENT;
95
96   // could check the validity of the cap too, however we just don't care
97   return i->unbind();
98 }
99
100 int
101 Sw_icu::set_mode(l4_msgtag_t /*tag*/, unsigned irqn, l4_umword_t mode)
102 {
103   Irq_set::Iterator i = _irqs.find(irqn);
104   if (i == _irqs.end())
105     return -L4_ENOENT;
106
107   if (i->l4_type() != (mode & 0x6))
108     {
109       d_printf(DBG_WARN, "WARNING: Changing type of IRQ %d from %x to %lx prohibited\n",
110              irqn, i->l4_type(), mode);
111       return 0;
112     }
113   return 0;
114 }
115
116 int
117 Sw_icu::unmask_irq(l4_msgtag_t /*tag*/, unsigned irqn)
118 {
119   Irq_set::Iterator i = _irqs.find(irqn);
120   if (i == _irqs.end())
121     return -L4_ENOENT;
122
123   if (!i->unmask_via_icu())
124     return -L4_EINVAL;
125
126   return i->unmask();
127 }
128
129
130 bool
131 Sw_icu::irqs_allocated(Adr_resource const *r)
132 {
133   for (unsigned n = r->_data().start(); n <= r->_data().end(); ++n)
134     {
135       if (_irqs.find(n) == _irqs.end())
136         return false;
137     }
138
139   return true;
140 }
141
142 bool
143 Sw_icu::add_irqs(Adr_resource const *r)
144 {
145   for (unsigned n = r->_data().start(); n <= r->_data().end(); ++n)
146     {
147       if (_irqs.find(n) != _irqs.end())
148         continue;
149
150       Sw_irq_pin *irq = new Sw_irq_pin(real_irq(n), n, r->flags());
151       _irqs.insert(irq);
152     }
153   return true;
154 }
155
156 bool
157 Sw_icu::add_irq(unsigned n, unsigned flags, Io_irq_pin *be)
158 {
159   if (_irqs.find(n) == _irqs.end())
160     return false;
161
162   Sw_irq_pin *irq = new Sw_irq_pin(be, n, flags);
163   _irqs.insert(irq);
164   return true;
165 }
166
167 int
168 Sw_icu::alloc_irq(unsigned flags, Io_irq_pin *be)
169 {
170   unsigned i;
171   for (i = 1; i < 1000; ++i)
172     if (_irqs.find(i) == _irqs.end())
173       break;
174
175   if (i == 1000)
176     return -1;
177
178   Sw_irq_pin *irq = new Sw_irq_pin(be, i, flags);
179   _irqs.insert(irq);
180   return i;
181 }
182
183
184 int
185 Sw_icu::dispatch(l4_umword_t /*obj*/, L4::Ipc_iostream &ios)
186 {
187   l4_umword_t op, irqn;
188   L4::Snd_fpage irqc;
189   l4_msgtag_t tag;
190   ios >> tag >> op >> irqn;
191
192   if (tag.label() != L4_PROTO_IRQ)
193     return -L4_EBADPROTO;
194
195   switch (op)
196     {
197     case L4_ICU_OP_BIND:
198       ios >> irqc;
199       return bind_irq(tag, irqn, irqc);
200
201     case L4_ICU_OP_UNBIND:
202       ios >> irqc;
203       return unbind_irq(tag, irqn, irqc);
204
205     case L4_ICU_OP_UNMASK:
206       unmask_irq(tag, irqn);
207       return -L4_ENOREPLY;
208
209     case L4_ICU_OP_SET_MODE:
210         {
211           l4_umword_t mode;
212           ios >> mode;
213           return set_mode(tag, irqn, mode);
214         }
215
216     default: return -L4_ENOSYS;
217     }
218 }
219
220 int
221 Sw_icu::dispatch(l4_umword_t, l4_uint32_t func, L4::Ipc_iostream &ios)
222 {
223   if (func != L4vbus_vicu_get_cap)
224     return -L4_ENOSYS;
225
226   ios << obj_cap();
227   return L4_EOK;
228 }
229
230 //static VBus_factory<Sw_icu> __vicu_factory("Vicu");
231
232 int
233 Sw_icu::Sw_irq_pin::trigger() const
234 {
235   return l4_error(_irq->trigger());
236 }
237
238
239 unsigned
240 Sw_icu::Sw_irq_pin::l4_type() const
241 {
242   unsigned m = type();
243   unsigned r = (m & S_irq_type_mask) / Adr_resource::Irq_info_factor;
244   return r;
245 }
246
247 void
248 Sw_icu::Sw_irq_pin::allocate_master_irq()
249 {
250   assert (_master->shared());
251   Auto_cap<L4::Irq>::Cap lirq = chkcap(L4Re::Util::cap_alloc.alloc<L4::Irq>(),
252       "allocating IRQ capability");
253   // printf("IRQ mode = %x -> %x\n", type(), l4_type());
254   chksys(L4Re::Env::env()->factory()->create(lirq.get(), L4_PROTO_IRQ) << l4_umword_t(1), "allocating IRQ");
255   chksys(_master->bind(lirq.get(), l4_type()), "binding IRQ");
256   _master->irq(lirq.release());
257   _master->set_chained(true);
258 }
259
260
261 int
262 Sw_icu::Sw_irq_pin::bind(L4::Cap<void> rc)
263 {
264   if (_irq.is_valid())
265     {
266       if (_irq.get().validate(L4Re::This_task).label() > 0)
267         return -L4_EEXIST;
268
269       _unbind();
270     }
271
272   if (bound())
273     return -L4_EPERM;
274
275   Auto_cap<L4::Irq>::Cap irq =
276     chkcap(L4Re::Util::cap_alloc.alloc<L4::Irq>(), "allocating IRQ capability");
277
278   irq.get().move(L4::cap_cast<L4::Irq>(rc));
279
280   if (_master->shared() && !_master->chained() && _master->sw_irqs() == 0)
281     {
282       allocate_master_irq();
283       assert (_master->chained());
284     }
285
286   if (!_master->chained())
287     {
288       // the first irq shall be attached to a hw irq
289       d_printf(DBG_DEBUG2, "IRQ %d -> client\nIRQ mode = %x -> %x\n",
290               irqn(), type(), l4_type());
291       int err = _master->bind(irq.get(), l4_type());
292       if (err < 0)
293         return err;
294
295       _irq = irq;
296       _master->irq(_irq.get());
297       _master->inc_sw_irqs();
298       _state |= S_bound;
299       if (err == 1)
300         _state |= S_unmask_via_icu;
301
302       d_printf(DBG_DEBUG2, "  bound irq %u -> err=%d\n", irqn(), err);
303       return err;
304     }
305
306   d_printf(DBG_DEBUG2, "IRQ %d -> proxy -> %d clients\n", irqn(), _master->sw_irqs() + 1);
307   L4Re::chksys(_master->irq()->chain(l4_umword_t(_master), irq.get()), "attach");
308   _irq = irq;
309   _master->inc_sw_irqs();
310
311   return 0;
312 }
313
314 int
315 Sw_icu::Sw_irq_pin::_unbind()
316 {
317   int err = 0;
318   _master->dec_sw_irqs();
319   if (_master->sw_irqs() == 0)
320     {
321       if (_master->chained())
322         L4Re::Util::cap_alloc.free(_master->irq());
323
324       _master->irq(L4::Cap<L4::Irq>::Invalid);
325       _master->set_chained(false);
326     }
327
328   _irq = L4::Cap<L4::Irq>::Invalid;
329
330   _state &= ~S_bound;
331   return err;
332 }
333
334 int
335 Sw_icu::Sw_irq_pin::unbind()
336 {
337   if (!_master)
338     return -L4_EINVAL;
339
340   if (!_master->sw_irqs())
341     return -L4_EINVAL;
342
343   return _unbind();
344 }
345
346 }