2015-05-01 20:03:08 +02:00
|
|
|
/*
|
|
|
|
* \brief Implementation of IRQ session component
|
|
|
|
* \author Norman Feske
|
|
|
|
* \date 2015-05-01
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2017-02-20 13:23:52 +01:00
|
|
|
* Copyright (C) 2015-2017 Genode Labs GmbH
|
2015-05-01 20:03:08 +02:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
2017-02-20 13:23:52 +01:00
|
|
|
* under the terms of the GNU Affero General Public License version 3.
|
2015-05-01 20:03:08 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* Genode includes */
|
2016-06-29 23:06:22 +02:00
|
|
|
#include <base/log.h>
|
2015-05-01 20:03:08 +02:00
|
|
|
|
|
|
|
/* core includes */
|
2016-06-29 23:06:22 +02:00
|
|
|
#include <platform.h>
|
2015-05-01 20:03:08 +02:00
|
|
|
#include <irq_root.h>
|
2016-06-29 23:06:22 +02:00
|
|
|
#include <irq_args.h>
|
2015-05-01 20:03:08 +02:00
|
|
|
|
2016-06-29 23:06:22 +02:00
|
|
|
#include <sel4/sel4.h>
|
2015-05-01 20:03:08 +02:00
|
|
|
|
|
|
|
using namespace Genode;
|
|
|
|
|
|
|
|
|
2016-06-29 23:06:22 +02:00
|
|
|
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();
|
|
|
|
|
2017-06-12 12:41:38 +02:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
2016-06-29 23:06:22 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2015-05-01 20:03:08 +02:00
|
|
|
|
|
|
|
|
|
|
|
void Irq_object::_wait_for_irq()
|
|
|
|
{
|
2016-06-29 23:06:22 +02:00
|
|
|
seL4_Wait(_kernel_notify_sel.value(), nullptr);
|
2015-05-01 20:03:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Irq_object::start()
|
|
|
|
{
|
2016-06-29 23:06:22 +02:00
|
|
|
::Thread::start();
|
|
|
|
_sync_bootup.lock();
|
2015-05-01 20:03:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Irq_object::entry()
|
|
|
|
{
|
2016-06-29 23:06:22 +02:00
|
|
|
/* thread is up and ready */
|
|
|
|
_sync_bootup.unlock();
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
|
|
|
|
_wait_for_irq();
|
|
|
|
|
|
|
|
if (!_sig_cap.valid())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
notify();
|
|
|
|
}
|
2015-05-01 20:03:08 +02:00
|
|
|
}
|
|
|
|
|
2016-06-29 23:06:22 +02:00
|
|
|
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);
|
|
|
|
}
|
2015-05-01 20:03:08 +02:00
|
|
|
|
|
|
|
Irq_object::Irq_object(unsigned irq)
|
|
|
|
:
|
2016-05-04 12:27:17 +02:00
|
|
|
Thread_deprecated<4096>("irq"),
|
2016-06-29 23:06:22 +02:00
|
|
|
_sync_bootup(Lock::LOCKED),
|
|
|
|
_irq(irq),
|
|
|
|
_kernel_irq_sel(platform_specific()->core_sel_alloc().alloc()),
|
|
|
|
_kernel_notify_sel(platform_specific()->core_sel_alloc().alloc())
|
2015-05-01 20:03:08 +02:00
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
|
|
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)
|
Streamline exception types
This patch reduces the number of exception types by facilitating
globally defined exceptions for common usage patterns shared by most
services. In particular, RPC functions that demand a session-resource
upgrade not longer reflect this condition via a session-specific
exception but via the 'Out_of_ram' or 'Out_of_caps' types.
Furthermore, the 'Parent::Service_denied', 'Parent::Unavailable',
'Root::Invalid_args', 'Root::Unavailable', 'Service::Invalid_args',
'Service::Unavailable', and 'Local_service::Factory::Denied' types have
been replaced by the single 'Service_denied' exception type defined in
'session/session.h'.
This consolidation eases the error handling (there are fewer exceptions
to handle), alleviates the need to convert exceptions along the
session-creation call chain, and avoids possible aliasing problems
(catching the wrong type with the same name but living in a different
scope).
2017-05-07 22:03:22 +02:00
|
|
|
throw Service_denied();
|
2015-05-01 20:03:08 +02:00
|
|
|
|
2016-05-11 18:21:47 +02:00
|
|
|
if (!irq_alloc || irq_alloc->alloc_addr(1, _irq_number).error()) {
|
Streamline exception types
This patch reduces the number of exception types by facilitating
globally defined exceptions for common usage patterns shared by most
services. In particular, RPC functions that demand a session-resource
upgrade not longer reflect this condition via a session-specific
exception but via the 'Out_of_ram' or 'Out_of_caps' types.
Furthermore, the 'Parent::Service_denied', 'Parent::Unavailable',
'Root::Invalid_args', 'Root::Unavailable', 'Service::Invalid_args',
'Service::Unavailable', and 'Local_service::Factory::Denied' types have
been replaced by the single 'Service_denied' exception type defined in
'session/session.h'.
This consolidation eases the error handling (there are fewer exceptions
to handle), alleviates the need to convert exceptions along the
session-creation call chain, and avoids possible aliasing problems
(catching the wrong type with the same name but living in a different
scope).
2017-05-07 22:03:22 +02:00
|
|
|
Genode::error("unavailable IRQ ", _irq_number, " requested");
|
|
|
|
throw Service_denied();
|
2016-06-29 23:06:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Irq_args const irq_args(args);
|
|
|
|
|
|
|
|
if (!_irq_object.associate(irq_args.trigger(), irq_args.polarity())) {
|
Streamline exception types
This patch reduces the number of exception types by facilitating
globally defined exceptions for common usage patterns shared by most
services. In particular, RPC functions that demand a session-resource
upgrade not longer reflect this condition via a session-specific
exception but via the 'Out_of_ram' or 'Out_of_caps' types.
Furthermore, the 'Parent::Service_denied', 'Parent::Unavailable',
'Root::Invalid_args', 'Root::Unavailable', 'Service::Invalid_args',
'Service::Unavailable', and 'Local_service::Factory::Denied' types have
been replaced by the single 'Service_denied' exception type defined in
'session/session.h'.
This consolidation eases the error handling (there are fewer exceptions
to handle), alleviates the need to convert exceptions along the
session-creation call chain, and avoids possible aliasing problems
(catching the wrong type with the same name but living in a different
scope).
2017-05-07 22:03:22 +02:00
|
|
|
Genode::error("could not associate with IRQ ", irq_args.irq_number());
|
|
|
|
throw Service_denied();
|
2015-05-01 20:03:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
_irq_object.start();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Irq_session_component::~Irq_session_component()
|
|
|
|
{
|
2016-06-29 23:06:22 +02:00
|
|
|
Genode::error(__PRETTY_FUNCTION__, "- not yet implemented.");
|
2015-05-01 20:03:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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 };
|
|
|
|
}
|