172 lines
4.0 KiB
C++
172 lines
4.0 KiB
C++
/*
|
|
* \brief Implementation of IRQ session component
|
|
* \author Norman Feske
|
|
* \date 2015-05-01
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2015-2017 Genode Labs GmbH
|
|
*
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
* under the terms of the GNU Affero General Public License version 3.
|
|
*/
|
|
|
|
/* Genode includes */
|
|
#include <base/log.h>
|
|
|
|
/* core includes */
|
|
#include <platform.h>
|
|
#include <irq_root.h>
|
|
#include <irq_args.h>
|
|
|
|
#include <sel4/sel4.h>
|
|
|
|
using namespace Genode;
|
|
|
|
|
|
bool Irq_object::associate(Irq_session::Trigger const irq_trigger,
|
|
Irq_session::Polarity const irq_polarity)
|
|
{
|
|
/* allocate notification object within core's CNode */
|
|
Platform &platform = *platform_specific();
|
|
Range_allocator &phys_alloc = *platform.ram_alloc();
|
|
|
|
{
|
|
addr_t const phys_addr = Untyped_memory::alloc_page(phys_alloc);
|
|
seL4_Untyped const service = Untyped_memory::untyped_sel(phys_addr).value();
|
|
|
|
create<Notification_kobj>(service, platform.core_cnode().sel(),
|
|
_kernel_notify_sel);
|
|
}
|
|
|
|
enum { IRQ_EDGE = 0, IRQ_LEVEL = 1 };
|
|
enum { IRQ_HIGH = 0, IRQ_LOW = 1 };
|
|
|
|
seL4_Word level = (_irq < 16) ? IRQ_EDGE : IRQ_LEVEL;
|
|
seL4_Word polarity = (_irq < 16) ? IRQ_HIGH : IRQ_LOW;
|
|
|
|
if (irq_trigger != Irq_session::TRIGGER_UNCHANGED)
|
|
level = (irq_trigger == Irq_session::TRIGGER_LEVEL) ? IRQ_LEVEL : IRQ_EDGE;
|
|
|
|
if (irq_polarity != Irq_session::POLARITY_UNCHANGED)
|
|
polarity = (irq_polarity == Irq_session::POLARITY_HIGH) ? IRQ_HIGH : IRQ_LOW;
|
|
|
|
/* setup irq */
|
|
seL4_CNode root = seL4_CapInitThreadCNode;
|
|
seL4_Word index = _kernel_irq_sel.value();
|
|
seL4_Uint8 depth = 32;
|
|
seL4_Word ioapic = 0;
|
|
seL4_Word pin = _irq ? _irq : 2;
|
|
seL4_Word vector = _irq;
|
|
int res = seL4_IRQControl_GetIOAPIC(seL4_CapIRQControl, root, index, depth,
|
|
ioapic, pin, level, polarity, vector);
|
|
if (res != seL4_NoError)
|
|
return false;
|
|
|
|
seL4_CPtr irq_handler = _kernel_irq_sel.value();
|
|
seL4_CPtr notification = _kernel_notify_sel.value();
|
|
|
|
res = seL4_IRQHandler_SetNotification(irq_handler, notification);
|
|
|
|
return (res == seL4_NoError);
|
|
}
|
|
|
|
|
|
void Irq_object::_wait_for_irq()
|
|
{
|
|
seL4_Wait(_kernel_notify_sel.value(), nullptr);
|
|
}
|
|
|
|
|
|
void Irq_object::start()
|
|
{
|
|
::Thread::start();
|
|
_sync_bootup.lock();
|
|
}
|
|
|
|
|
|
void Irq_object::entry()
|
|
{
|
|
/* thread is up and ready */
|
|
_sync_bootup.unlock();
|
|
|
|
while (true) {
|
|
|
|
_wait_for_irq();
|
|
|
|
if (!_sig_cap.valid())
|
|
continue;
|
|
|
|
notify();
|
|
}
|
|
}
|
|
|
|
void Genode::Irq_object::ack_irq()
|
|
{
|
|
int res = seL4_IRQHandler_Ack(_kernel_irq_sel.value());
|
|
if (res != seL4_NoError)
|
|
Genode::error("ack_irq failed - ", res);
|
|
}
|
|
|
|
Irq_object::Irq_object(unsigned irq)
|
|
:
|
|
Thread_deprecated<4096>("irq"),
|
|
_sync_bootup(Lock::LOCKED),
|
|
_irq(irq),
|
|
_kernel_irq_sel(platform_specific()->core_sel_alloc().alloc()),
|
|
_kernel_notify_sel(platform_specific()->core_sel_alloc().alloc())
|
|
{ }
|
|
|
|
|
|
Irq_session_component::Irq_session_component(Range_allocator *irq_alloc,
|
|
const char *args)
|
|
:
|
|
_irq_number(Arg_string::find_arg(args, "irq_number").long_value(-1)),
|
|
_irq_alloc(irq_alloc),
|
|
_irq_object(_irq_number)
|
|
{
|
|
long msi = Arg_string::find_arg(args, "device_config_phys").long_value(0);
|
|
if (msi)
|
|
throw Service_denied();
|
|
|
|
if (!irq_alloc || irq_alloc->alloc_addr(1, _irq_number).error()) {
|
|
Genode::error("unavailable IRQ ", _irq_number, " requested");
|
|
throw Service_denied();
|
|
}
|
|
|
|
|
|
Irq_args const irq_args(args);
|
|
|
|
if (!_irq_object.associate(irq_args.trigger(), irq_args.polarity())) {
|
|
Genode::error("could not associate with IRQ ", irq_args.irq_number());
|
|
throw Service_denied();
|
|
}
|
|
|
|
_irq_object.start();
|
|
}
|
|
|
|
|
|
Irq_session_component::~Irq_session_component()
|
|
{
|
|
Genode::error(__PRETTY_FUNCTION__, "- not yet implemented.");
|
|
}
|
|
|
|
|
|
void Irq_session_component::ack_irq()
|
|
{
|
|
_irq_object.ack_irq();
|
|
}
|
|
|
|
|
|
void Irq_session_component::sigh(Genode::Signal_context_capability cap)
|
|
{
|
|
_irq_object.sigh(cap);
|
|
}
|
|
|
|
|
|
Genode::Irq_session::Info Irq_session_component::info()
|
|
{
|
|
/* no MSI support */
|
|
return { .type = Genode::Irq_session::Info::Type::INVALID };
|
|
}
|