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