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