]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/io/server/src/vbus.cc
update
[l4.git] / l4 / pkg / io / server / src / vbus.cc
1 /*
2  * (c) 2010 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
3  *          Alexander Warg <warg@os.inf.tu-dresden.de>
4  *     economic rights: Technische Universität Dresden (Germany)
5  *
6  * This file is part of TUD:OS and distributed under the terms of the
7  * GNU General Public License 2.
8  * Please see the COPYING-GPL-2 file for details.
9  */
10 #include <l4/re/protocols>
11
12 #include <l4/cxx/ipc_server>
13 #include <l4/cxx/iostream>
14 #include <l4/cxx/l4iostream>
15
16 #include <l4/re/env>
17 #include <l4/re/namespace>
18 #include <l4/re/dataspace-sys.h>
19
20 #include <l4/re/error_helper>
21
22 #include <l4/vbus/vbus_types.h>
23 #include <l4/vbus/vdevice-ops.h>
24
25 #include <cstdio>
26
27 #include "debug.h"
28 #include "hw_msi.h"
29 #include "vbus.h"
30 #include "vmsi.h"
31 #include "vicu.h"
32 #include "server.h"
33 #include "res.h"
34 #include "cfg.h"
35 #include "vbus_factory.h"
36
37 namespace {
38
39 class Root_irq_rs : public Resource_space
40 {
41 private:
42   Vi::System_bus *_bus;
43   Vi::Sw_icu *_icu;
44
45 public:
46   Root_irq_rs(Vi::System_bus *bus) : Resource_space(), _bus(bus), _icu(0)
47   {}
48
49   bool request(Resource *parent, Device *, Resource *child, Device *)
50   {
51     // printf("VBUS: IRQ resource request: "); child->dump();
52     Adr_resource *r = dynamic_cast<Adr_resource*>(child);
53     if (!r || !parent)
54       return false;
55
56     if (!_icu)
57       {
58         _icu = new Vi::Sw_icu();
59         _bus->add_child(_icu);
60       }
61
62     d_printf(DBG_DEBUG2, "Add IRQ resources to vbus: ");
63     if (dlevel(DBG_DEBUG2))
64       child->dump();
65
66     _icu->add_irqs(r);
67     _bus->resource_set()->insert(r);
68
69     return true;
70   };
71
72   bool alloc(Resource *parent, Device *, Resource *child, Device *, bool)
73   {
74     d_printf(DBG_DEBUG2, "Allocate virtual IRQ resource ...\n");
75     if (dlevel(DBG_DEBUG2))
76       child->dump();
77
78     Vi::Msi_resource *msi = dynamic_cast<Vi::Msi_resource*>(child);
79     if (!msi || !parent)
80       return false;
81
82     d_printf(DBG_DEBUG2, "  Allocate Virtual MSI...\n");
83
84     if (!_icu)
85       {
86         _icu = new Vi::Sw_icu();
87         _bus->add_child(_icu);
88       }
89
90     int nr = _icu->alloc_irq(msi->flags(), msi->hw_msi());
91     if (nr < 0)
92       {
93         d_printf(DBG_ERR, "ERROR: cannot allocate MSI resource\n");
94         return false;
95       }
96
97     msi->start_end(nr, nr);
98     msi->del_flags(Resource::F_disabled);
99
100     if (dlevel(DBG_DEBUG2))
101       {
102         msi->dump(4);
103         msi->hw_msi()->dump(4);
104       }
105
106     _bus->resource_set()->insert(msi);
107     return true;
108   }
109
110   ~Root_irq_rs() {}
111 };
112
113 class Root_x_rs : public Resource_space
114 {
115 private:
116   Vi::System_bus *_bus;
117
118 public:
119   Root_x_rs(Vi::System_bus *bus) : Resource_space(), _bus(bus)
120   {}
121
122   bool request(Resource *parent, Device *, Resource *child, Device *)
123   {
124     //printf("VBUS: X resource request: "); child->dump();
125     Adr_resource *r = dynamic_cast<Adr_resource*>(child);
126     if (!r || !parent)
127       return false;
128
129
130     _bus->resource_set()->insert(r);
131     return true;
132   }
133
134   bool alloc(Resource *, Device *, Resource *, Device *, bool)
135   { return false; }
136
137   ~Root_x_rs() {}
138 };
139 }
140
141
142
143 namespace Vi {
144
145 bool
146 System_bus::resource_allocated(Resource const *_r) const
147 {
148   Adr_resource const *r = dynamic_cast<Adr_resource const *>(_r);
149   if (!r)
150     return false;
151
152   Resource_set::const_iterator i = _resources.find(const_cast<Adr_resource*>(r));
153   if (i == _resources.end())
154     return false;
155
156   if ((*i)->data().start() <= r->data().start()
157       && (*i)->data().end() >= r->data().end())
158     return true;
159
160   return false;
161 }
162
163
164 System_bus::System_bus()
165 {
166   add_feature(this);
167   add_resource(new Root_resource(Resource::Irq_res, new Root_irq_rs(this)));
168   Resource_space *x = new Root_x_rs(this);
169   add_resource(new Root_resource(Resource::Mmio_res, x));
170   add_resource(new Root_resource(Resource::Mmio_res | Resource::F_prefetchable, x));
171   add_resource(new Root_resource(Resource::Io_res, x));
172 }
173
174 System_bus::~System_bus()
175 {
176   registry->unregister_obj(this);
177   // FIXME: must delete all devices
178 }
179
180
181 void
182 System_bus::dump_resources() const
183 {
184   for (Resource_set::const_iterator i = _resources.begin(); i != _resources.end(); ++i)
185     (*i)->dump();
186 }
187
188 int
189 System_bus::request_resource(L4::Ipc_iostream &ios)
190 {
191   l4vbus_resource_t res;
192   ios.get(res);
193
194   ::Adr_resource ires(res.type, res.start, res.end);
195   if (dlevel(DBG_DEBUG2))
196     {
197       printf("request resource: ");
198       Adr_resource(ires).dump();
199       puts("");
200     }
201
202   Resource_set::const_iterator i = _resources.find(&ires);
203 #if 0
204   for (Resource_set::Const_iterator m = _resources.begin(); m != _resources.end(); ++m)
205     {
206       m->dump();
207       puts("");
208     }
209 #endif
210
211   if (i == _resources.end() || !(*i)->contains(ires))
212     return -L4_ENOENT;
213
214 #if 0
215   if (Io_config::cfg->verbose() > 1)
216     {
217       printf("  found resource: ");
218       i->dump();
219       puts("");
220     }
221 #endif
222
223   if (res.type == L4VBUS_RESOURCE_PORT)
224     {
225       l4_uint64_t sz = res.end + 1 - res.start;
226
227       int szl2 = 0;
228       while ((1UL << szl2) < sz)
229         ++szl2;
230
231       if ((1UL << szl2) > sz)
232         --szl2;
233
234       ios << L4::Snd_fpage::io(res.start, szl2, L4_FPAGE_RWX);
235       return L4_EOK;
236     }
237
238
239   return -L4_ENOENT;
240 }
241
242 int
243 System_bus::request_iomem(L4::Ipc_iostream &ios)
244 {
245   L4::Opcode op;
246   ios >> op;
247   switch (op)
248     {
249     case L4Re::Dataspace_::Map:
250         {
251           l4_addr_t offset, spot;
252           unsigned long flags;
253           ios >> offset >> spot >> flags;
254
255 //        printf("map iomem: %lx...\n", offset);
256           Adr_resource pivot(L4VBUS_RESOURCE_MEM, offset, offset);
257           Resource_set::iterator r = _resources.find(&pivot);
258
259           if (r == _resources.end())
260             return -L4_ERANGE;
261
262           offset = l4_trunc_page(offset);
263
264           l4_addr_t st = l4_trunc_page((*r)->start());
265           l4_addr_t adr = (*r)->map_iomem();
266
267           if (!adr)
268             return -L4_ENOMEM;
269
270           adr = l4_trunc_page(adr);
271
272           l4_addr_t addr = offset - st + adr;
273           unsigned char order
274             = l4_fpage_max_order(L4_PAGESHIFT,
275                                  addr, addr, addr + (*r)->size(), spot);
276
277           // we also might want to do WB instead of UNCACHED...
278           ios << L4::Snd_fpage::mem(l4_trunc_size(addr, order), order,
279                                     L4_FPAGE_RWX, l4_trunc_page(spot),
280                                     L4::Snd_fpage::Map,
281                                     L4::Snd_fpage::Uncached);
282           return L4_EOK;
283         }
284     }
285   return -L4_ENOSYS;
286 };
287
288 int
289 System_bus::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
290 {
291   l4_msgtag_t tag;
292   ios >> tag;
293
294   if (tag.label() == 0)
295     {
296       l4vbus_device_handle_t devid;
297       l4_uint32_t func;
298       ios >> devid >> func;
299       Device *dev = get_dev_by_id(devid);
300       if (!dev)
301         return -L4_ENODEV;
302       return dev->vdevice_dispatch(obj, func, ios);
303     }
304
305   if (tag.label() == L4Re::Protocol::Dataspace)
306     return request_iomem(ios);
307
308   return -L4_EBADPROTO;
309
310 }
311
312 int
313 System_bus::dispatch(l4_umword_t, l4_uint32_t func, L4::Ipc_iostream &ios)
314 {
315   switch (func)
316     {
317     case L4vbus_vbus_request_resource:
318       return request_resource(ios);
319     default:
320       return -L4_ENOSYS;
321     }
322 }
323
324
325 static Dev_factory_t<System_bus> __sb_root_factory("System_bus");
326
327 }