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