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)
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.
10 #include <l4/re/protocols>
12 #include <l4/cxx/ipc_server>
15 #include <l4/re/namespace>
16 #include <l4/re/dataspace-sys.h>
17 #include <l4/re/inhibitor-sys.h>
19 #include <l4/re/error_helper>
21 #include <l4/vbus/vbus_types.h>
22 #include <l4/vbus/vdevice-ops.h>
34 #include "vbus_factory.h"
36 Vi::System_bus::Root_resource_factory::Factory_list
37 Vi::System_bus::Root_resource_factory::_factories;
41 class Root_irq_rs : public Resource_space
48 Root_irq_rs(Vi::System_bus *bus)
49 : Resource_space(), _bus(bus), _icu(new Vi::Sw_icu())
51 _bus->add_child(_icu);
56 bool request(Resource *parent, Device *, Resource *child, Device *)
60 printf("VBUS: IRQ resource request: ");
69 _icu = new Vi::Sw_icu();
70 _bus->add_child(_icu);
74 d_printf(DBG_DEBUG2, "Add IRQ resources to vbus: ");
75 if (dlevel(DBG_DEBUG2))
78 _icu->add_irqs(child);
79 return _bus->add_resource_to_bus(child);
82 bool alloc(Resource *parent, Device *, Resource *child, Device *, bool)
84 d_printf(DBG_DEBUG2, "Allocate virtual IRQ resource ...\n");
85 if (dlevel(DBG_DEBUG2))
88 Vi::Msi_resource *msi = dynamic_cast<Vi::Msi_resource*>(child);
92 d_printf(DBG_DEBUG2, " Allocate Virtual MSI...\n");
96 _icu = new Vi::Sw_icu();
97 _bus->add_child(_icu);
100 int nr = _icu->alloc_irq(msi->flags(), msi->hw_msi());
103 d_printf(DBG_ERR, "ERROR: cannot allocate MSI resource\n");
107 msi->start_end(nr, nr);
108 msi->del_flags(Resource::F_disabled);
110 if (dlevel(DBG_DEBUG2))
113 msi->hw_msi()->dump(4);
116 return _bus->add_resource_to_bus(msi);
122 class Root_x_rs : public Resource_space
125 Vi::System_bus *_bus;
128 Root_x_rs(Vi::System_bus *bus) : Resource_space(), _bus(bus)
131 bool request(Resource *parent, Device *, Resource *child, Device *)
135 printf("VBUS: X resource request: ");
143 return _bus->add_resource_to_bus(child);
146 bool alloc(Resource *, Device *, Resource *, Device *, bool)
157 System_bus::System_bus(Inhibitor_mux *mux)
158 : Inhibitor_provider(mux), _sw_icu(0)
161 add_resource(new Root_resource(Resource::Irq_res, new Root_irq_rs(this)));
162 Resource_space *x = new Root_x_rs(this);
163 add_resource(new Root_resource(Resource::Mmio_res, x));
164 add_resource(new Root_resource(Resource::Mmio_res | Resource::F_prefetchable, x));
165 add_resource(new Root_resource(Resource::Io_res, x));
166 typedef Root_resource_factory RF;
167 for (RF::Factory_list::Const_iterator i = RF::_factories.begin();
168 i != RF::_factories.end();
170 add_resource((*i)->create(this));
173 System_bus::~System_bus()
175 registry->unregister_obj(this);
176 // FIXME: must delete all devices
180 * \brief Add the region described by \a r to the VBUS resources.
182 * Adds the resource to the resources available through this V-BUS.
183 * This also supports overlapping resources by merging them together.
186 System_bus::add_resource_to_bus(Resource *r)
188 auto x = _resources.find(r);
189 if (x == _resources.end())
191 _resources.insert(r);
195 // overlapping resource entry already found
196 if (typeid (*r) != typeid (**x))
200 printf("error: overlapping incompatible resources for vbus\n");
201 printf(" new: "); r->dump(); puts(" conflicts with");
202 printf(" found: "); (*x)->dump(); puts("");
207 if ((*x)->contains(*r))
208 // already fully included
211 if (r->contains(**x))
214 _resources.insert(r);
220 printf("error: oddly overlaping resources for vbus\n");
221 printf(" new: "); r->dump(); puts(" confilicts with");
222 printf(" found: "); (*x)->dump(); puts("");
228 System_bus::resource_allocated(Resource const *r) const
233 auto i = _resources.find(const_cast<Resource *>(r));
234 if (i == _resources.end())
237 return (*i)->contains(*r);
241 System_bus::pm_suspend()
243 inhibitor_release(L4VBUS_INHIBITOR_SUSPEND);
249 System_bus::pm_resume()
251 inhibitor_acquire(L4VBUS_INHIBITOR_SUSPEND, "vbus active");
257 System_bus::dump_resources() const
259 for (auto i = _resources.begin();
260 i != _resources.end(); ++i)
265 System_bus::request_resource(L4::Ipc::Iostream &ios)
267 l4vbus_resource_t res;
270 Resource ires(res.type, res.start, res.end);
271 if (dlevel(DBG_DEBUG2))
273 printf("request resource: ");
278 auto i = _resources.find(&ires);
283 if (i == _resources.end() || !(*i)->contains(ires))
287 if (dlevel(DBG_DEBUG))
289 printf(" found resource: ");
294 if (res.type == L4VBUS_RESOURCE_PORT)
296 l4_uint64_t sz = res.end + 1 - res.start;
299 while ((1UL << szl2) < sz)
302 if ((1UL << szl2) > sz)
305 ios << L4::Ipc::Snd_fpage::io(res.start, szl2, L4_FPAGE_RWX);
314 System_bus::request_iomem(L4::Ipc::Iostream &ios)
320 case L4Re::Dataspace_::Map:
322 l4_addr_t offset, spot;
324 ios >> offset >> spot >> flags;
326 Resource pivot(L4VBUS_RESOURCE_MEM, offset, offset);
327 auto r = _resources.find(&pivot);
329 if (r == _resources.end())
331 if (dlevel(DBG_INFO))
333 printf("Request: No resource at %lx\n", offset);
334 printf("Available resources:\n");
340 offset = l4_trunc_page(offset);
342 l4_addr_t st = l4_trunc_page((*r)->start());
343 l4_addr_t adr = (*r)->map_iomem();
348 adr = l4_trunc_page(adr);
350 l4_addr_t addr = offset - st + adr;
352 = l4_fpage_max_order(L4_PAGESHIFT,
353 addr, addr, addr + (*r)->size(), spot);
355 // we also might want to do WB instead of UNCACHED...
356 ios << L4::Ipc::Snd_fpage::mem(l4_trunc_size(addr, order), order,
357 L4_FPAGE_RWX, l4_trunc_page(spot),
358 L4::Ipc::Snd_fpage::Map,
359 L4::Ipc::Snd_fpage::Uncached);
367 System_bus::inhibitor_dispatch(L4::Ipc::Iostream &ios)
374 case L4Re::Inhibitor_::Acquire:
375 inhibitor_acquire(ios);
377 case L4Re::Inhibitor_::Release:
381 inhibitor_release(id);
384 case L4Re::Inhibitor_::Next_lock_info:
389 if (id >= L4VBUS_INHIBITOR_MAX)
392 static char const *const names[] =
394 /* [L4VBUS_INHIBITOR_SUSPEND] = */ "suspend",
395 /* [L4VBUS_INHIBITOR_SHUTDOWN] = */ "shutdown",
396 /* [L4VBUS_INHIBITOR_WAKEUP] = */ "wakeup"
399 ios << (l4_umword_t)id << names[id];
408 System_bus::dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios)
415 case L4_PROTO_IRQ: // The ICU for event source
416 case L4Re::Protocol::Event:
417 return Vbus_event_source::dispatch(obj, ios);
418 case L4Re::Protocol::Inhibitor:
419 return inhibitor_dispatch(ios);
421 case L4Re::Protocol::Dataspace:
422 return request_iomem(ios);
426 l4vbus_device_handle_t devid;
428 ios >> devid >> func;
429 Device *dev = get_dev_by_id(devid);
432 return dev->vdevice_dispatch(obj, func, ios);
436 return -L4_EBADPROTO;
442 System_bus::dispatch(l4_umword_t, l4_uint32_t func, L4::Ipc::Iostream &ios)
446 case L4vbus_vbus_request_resource:
447 return request_resource(ios);
453 Vbus_event_source::Vbus_event_source()
455 using L4Re::Util::Auto_cap;
459 Auto_cap<L4Re::Dataspace>::Cap buffer_ds
460 = chkcap(L4Re::Util::cap_alloc.alloc<L4Re::Dataspace>(),
461 "allocate event-buffer data-space capability");
463 chksys(L4Re::Env::env()->mem_alloc()->alloc(L4_PAGESIZE, buffer_ds.get()),
464 "allocate event-buffer data-space");
466 chksys(buffer.attach(buffer_ds.get(), L4Re::Env::env()->rm()),
467 "attach event-buffer data-space");
469 _ds = buffer_ds.release();
473 * \brief Send device notification to client.
475 * \param dev device the notification is originating from.
476 * \param type event type to be sent, see event_enums.h for types.
477 * \param event event ID.
478 * \param value value for the event.
479 * \param syn trigger an IRQ for the event if true.
482 System_bus::dev_notify(Device const *dev, unsigned type,
483 unsigned event, unsigned value, bool syn)
485 Vbus_event_source::Event ev;
486 ev.time = l4_kip_clock(l4re_kip());
487 ev.payload.type = type;
488 ev.payload.code = event;
489 ev.payload.value = value;
490 ev.payload.stream_id = (l4vbus_device_handle_t)dev;
492 return Vbus_event_source::put(ev, syn);
496 System_bus::get_stream_info_for_id(l4_umword_t dev_id, L4Re::Event_stream_info *info)
498 Device *dev = get_dev_by_id(dev_id);
502 Io::Event_source_infos const *_info = dev->get_event_infos();
511 System_bus::get_stream_state_for_id(l4_umword_t dev_id, L4Re::Event_stream_state *state)
513 Device *dev = get_dev_by_id(dev_id);
517 Io::Event_source_infos const *_info = dev->get_event_infos();
521 *state = _info->state;
526 Vbus_event_source::rcv_cap()
532 System_bus::inhibitor_signal(l4_umword_t id)
534 // FIXME: need a subscribed flag!
535 // only signal if this inhibitor is actually acquired
536 if (!inhibitor_acquired(id))
539 Vbus_event_source::Event ev;
540 ev.time = l4_kip_clock(l4re_kip());
541 ev.payload.type = L4RE_EV_PM;
542 ev.payload.code = id;
543 ev.payload.value = 1;
544 ev.payload.stream_id = (l4vbus_device_handle_t)0;