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