base: make irq_session asynchronous

second step

options: factor out common parts of irq_session_component.cc
options: use on foc arm no proxy threads

Fixes #1456
This commit is contained in:
Alexander Boettcher 2015-03-17 15:41:47 +01:00 committed by Christian Helmuth
parent e2cbc7c5b3
commit faa25e1df6
36 changed files with 872 additions and 1132 deletions

View File

@ -1,72 +0,0 @@
/*
* \brief IRQ session interface for NOVA
* \author Norman Feske
* \date 2010-01-30
*/
/*
* Copyright (C) 2010-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_
#define _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_
#include <base/lock.h>
#include <util/list.h>
#include <irq_session/capability.h>
namespace Genode {
class Irq_session_component : public Rpc_object<Irq_session>,
public List<Irq_session_component>::Element
{
private:
enum { STACK_SIZE = 4096 };
unsigned _irq_number;
Range_allocator *_irq_alloc;
Rpc_entrypoint _entrypoint;
Irq_session_capability _cap;
bool _attached;
public:
/**
* Constructor
*
* \param cap_session capability session to use
* \param irq_alloc platform-dependent IRQ allocator
* \param args session construction arguments
*/
Irq_session_component(Cap_session *cap_session,
Range_allocator *irq_alloc,
const char *args);
/**
* Destructor
*/
~Irq_session_component();
/**
* Return capability to this session
*
* If an initialization error occurs, returned capability is invalid.
*/
Irq_session_capability cap() const { return _cap; }
/***************************
** Irq session interface **
***************************/
void wait_for_irq();
Irq_signal signal();
};
}
#endif /* _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_ */

View File

@ -22,57 +22,123 @@
#include <codezero/syscalls.h> #include <codezero/syscalls.h>
namespace Genode {
typedef Irq_proxy<Thread<1024 * sizeof(addr_t)> > Irq_proxy_base;
class Irq_proxy_component;
}
using namespace Genode; using namespace Genode;
/**
* Platform-specific proxy code
*/
void Irq_session_component::wait_for_irq() class Genode::Irq_proxy_component : public Irq_proxy_base
{ {
using namespace Codezero; private:
/* attach thread to IRQ when first called */ bool _irq_attached;
if (!_attached) {
int ret = l4_irq_control(IRQ_CONTROL_REGISTER, 0, _irq_number); protected:
if (ret < 0) {
PERR("l4_irq_control(IRQ_CONTROL_REGISTER) returned %d", ret); bool _associate() { return true; }
sleep_forever();
void _wait_for_irq()
{
using namespace Codezero;
/* attach thread to IRQ when first called */
if (!_irq_attached) {
int ret = l4_irq_control(IRQ_CONTROL_REGISTER, 0, _irq_number);
if (ret < 0) {
PERR("l4_irq_control(IRQ_CONTROL_REGISTER) returned %d", ret);
sleep_forever();
}
_irq_attached = true;
}
/* block for IRQ */
int ret = l4_irq_control(IRQ_CONTROL_WAIT, 0, _irq_number);
if (ret < 0)
PWRN("l4_irq_control(IRQ_CONTROL_WAIT) returned %d", ret);
} }
_attached = true;
void _ack_irq() { }
public:
Irq_proxy_component(long irq_number)
:
Irq_proxy(irq_number),
_irq_attached(false)
{
_start();
}
};
/***************************
** IRQ session component **
***************************/
void Irq_session_component::ack_irq()
{
if (!_proxy) {
PERR("Expected to find IRQ proxy for IRQ %02x", _irq_number);
return;
} }
/* block for IRQ */ _proxy->ack_irq();
int ret = l4_irq_control(IRQ_CONTROL_WAIT, 0, _irq_number);
if (ret < 0)
PWRN("l4_irq_control(IRQ_CONTROL_WAIT) returned %d", ret);
} }
Irq_session_component::Irq_session_component(Cap_session *cap_session, Irq_session_component::Irq_session_component(Range_allocator *irq_alloc,
Range_allocator *irq_alloc,
const char *args) const char *args)
: :
_irq_alloc(irq_alloc), _irq_alloc(irq_alloc)
_entrypoint(cap_session, STACK_SIZE, "irq"),
_attached(false)
{ {
long irq_number = Arg_string::find_arg(args, "irq_number").long_value(-1); long irq_number = Arg_string::find_arg(args, "irq_number").long_value(-1);
if (!irq_alloc || (irq_number == -1)|| if (irq_number == -1) {
irq_alloc->alloc_addr(1, irq_number).is_error()) { PERR("invalid IRQ number requested");
PERR("unavailable IRQ %lx requested", irq_number);
return; throw Root::Unavailable();
} }
/* check if IRQ thread was started before */
_proxy = Irq_proxy_component::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc);
if (!_proxy) {
PERR("unavailable IRQ %lx requested", irq_number);
throw Root::Unavailable();
}
_irq_number = irq_number; _irq_number = irq_number;
_cap = Irq_session_capability(_entrypoint.manage(this));
} }
Irq_session_component::~Irq_session_component() Irq_session_component::~Irq_session_component()
{ {
PERR("not yet implemented"); if (!_proxy) return;
if (_irq_sigh.valid())
_proxy->remove_sharer(&_irq_sigh);
} }
Irq_signal Irq_session_component::signal() void Irq_session_component::sigh(Genode::Signal_context_capability sigh)
{ {
PDBG("not implemented;"); if (!_proxy) {
return Irq_signal(); PERR("signal handler got not registered - irq thread unavailable");
return;
}
Genode::Signal_context_capability old = _irq_sigh;
if (old.valid() && !sigh.valid())
_proxy->remove_sharer(&_irq_sigh);
_irq_sigh = sigh;
if (!old.valid() && sigh.valid())
_proxy->add_sharer(&_irq_sigh);
} }

View File

@ -18,6 +18,7 @@
#include <util/arg_string.h> #include <util/arg_string.h>
/* core includes */ /* core includes */
#include <irq_proxy.h>
#include <irq_root.h> #include <irq_root.h>
#include <util.h> #include <util.h>
@ -28,101 +29,150 @@ namespace Fiasco {
#include <l4/sys/types.h> #include <l4/sys/types.h>
} }
namespace Genode {
typedef Irq_proxy<Thread<1024 * sizeof(addr_t)> > Irq_proxy_base;
class Irq_proxy_component;
}
using namespace Genode; using namespace Genode;
bool Irq_session_component::Irq_control_component::associate_to_irq(unsigned irq_number) /**
* Platform-specific proxy code
*/
class Genode::Irq_proxy_component : public Irq_proxy_base
{ {
using namespace Fiasco; protected:
int err; bool _associate()
l4_threadid_t irq_tid; {
l4_umword_t dw0, dw1; using namespace Fiasco;
l4_msgdope_t result;
l4_make_taskid_from_irq(irq_number, &irq_tid); int err;
l4_threadid_t irq_tid;
l4_umword_t dw0, dw1;
l4_msgdope_t result;
/* boost thread to IRQ priority */ l4_make_taskid_from_irq(_irq_number, &irq_tid);
enum { IRQ_PRIORITY = 0xC0 };
l4_sched_param_t param = {sp:{prio:IRQ_PRIORITY, small:0, state:0, time_exp:0, time_man:0}}; /* boost thread to IRQ priority */
l4_threadid_t ext_preempter = L4_INVALID_ID; enum { IRQ_PRIORITY = 0xC0 };
l4_threadid_t partner = L4_INVALID_ID;
l4_sched_param_t old_param;
l4_thread_schedule(l4_myself(), param, &ext_preempter, &partner, &old_param);
err = l4_ipc_receive(irq_tid, l4_sched_param_t param = {sp:{prio:IRQ_PRIORITY, small:0, state:0,
L4_IPC_SHORT_MSG, &dw0, &dw1, time_exp:0, time_man:0}};
L4_IPC_BOTH_TIMEOUT_0, &result); l4_threadid_t ext_preempter = L4_INVALID_ID;
l4_threadid_t partner = L4_INVALID_ID;
l4_sched_param_t old_param;
l4_thread_schedule(l4_myself(), param, &ext_preempter, &partner,
&old_param);
if (err != L4_IPC_RETIMEOUT) PERR("IRQ association failed"); err = l4_ipc_receive(irq_tid,
L4_IPC_SHORT_MSG, &dw0, &dw1,
L4_IPC_BOTH_TIMEOUT_0, &result);
return (err == L4_IPC_RETIMEOUT); if (err != L4_IPC_RETIMEOUT) PERR("IRQ association failed");
return (err == L4_IPC_RETIMEOUT);
}
void _wait_for_irq()
{
using namespace Fiasco;
l4_threadid_t irq_tid;
l4_umword_t dw0=0, dw1=0;
l4_msgdope_t result;
l4_make_taskid_from_irq(_irq_number, &irq_tid);
do {
l4_ipc_call(irq_tid,
L4_IPC_SHORT_MSG, 0, 0,
L4_IPC_SHORT_MSG, &dw0, &dw1,
L4_IPC_NEVER, &result);
if (L4_IPC_IS_ERROR(result))
PERR("Ipc error %lx", L4_IPC_ERROR(result));
} while (L4_IPC_IS_ERROR(result));
}
void _ack_irq() { }
public:
Irq_proxy_component(long irq_number)
:
Irq_proxy(irq_number)
{
_start();
}
};
/***************************
** IRQ session component **
***************************/
void Irq_session_component::ack_irq()
{
if (!_proxy) {
PERR("Expected to find IRQ proxy for IRQ %02x", _irq_number);
return;
}
_proxy->ack_irq();
} }
void Irq_session_component::wait_for_irq() Irq_session_component::Irq_session_component(Range_allocator *irq_alloc,
{
using namespace Fiasco;
l4_threadid_t irq_tid;
l4_umword_t dw0=0, dw1=0;
l4_msgdope_t result;
l4_make_taskid_from_irq(_irq_number, &irq_tid);
do {
l4_ipc_call(irq_tid,
L4_IPC_SHORT_MSG, 0, 0,
L4_IPC_SHORT_MSG, &dw0, &dw1,
L4_IPC_NEVER, &result);
if (L4_IPC_IS_ERROR(result)) PERR("Ipc error %lx", L4_IPC_ERROR(result));
} while (L4_IPC_IS_ERROR(result));
}
Irq_session_component::Irq_session_component(Cap_session *cap_session,
Range_allocator *irq_alloc,
const char *args) const char *args)
: :
_irq_alloc(irq_alloc), _irq_alloc(irq_alloc)
_ep(cap_session, STACK_SIZE, "irqctrl"),
_control_cap(_ep.manage(&_control_component)),
_control_client(_control_cap)
{ {
bool shared = Arg_string::find_arg(args, "irq_shared").bool_value(false);
if (shared) {
PWRN("IRQ sharing not supported");
throw Root::Invalid_args();
}
long irq_number = Arg_string::find_arg(args, "irq_number").long_value(-1); long irq_number = Arg_string::find_arg(args, "irq_number").long_value(-1);
if (irq_number == -1 || !irq_alloc || if (irq_number == -1) {
irq_alloc->alloc_addr(1, irq_number).is_error()) { PERR("invalid IRQ number requested");
PERR("Unavailable IRQ %lx requested", irq_number);
throw Root::Invalid_args(); throw Root::Unavailable();
} }
/* check if IRQ thread was started before */
_proxy = Irq_proxy_component::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc);
if (!_proxy) {
PERR("unavailable IRQ %lx requested", irq_number);
throw Root::Unavailable();
}
_irq_number = irq_number; _irq_number = irq_number;
if (!_control_client.associate_to_irq(irq_number)) {
PWRN("IRQ association failed");
throw Root::Invalid_args();
}
/* initialize capability */
_irq_cap = Irq_session_capability(_ep.manage(this));
} }
Irq_session_component::~Irq_session_component() Irq_session_component::~Irq_session_component()
{ {
PERR("Implement me, immediately!"); if (!_proxy) return;
if (_irq_sigh.valid())
_proxy->remove_sharer(&_irq_sigh);
} }
Irq_signal Irq_session_component::signal() void Irq_session_component::sigh(Genode::Signal_context_capability sigh)
{ {
PDBG("not implemented;"); if (!_proxy) {
return Irq_signal(); PERR("signal handler got not registered - irq thread unavailable");
return;
}
Genode::Signal_context_capability old = _irq_sigh;
if (old.valid() && !sigh.valid())
_proxy->remove_sharer(&_irq_sigh);
_irq_sigh = sigh;
if (!old.valid() && sigh.valid())
_proxy->add_sharer(&_irq_sigh);
} }

View File

@ -4,6 +4,5 @@ LD_TEXT_ADDR = 0x80100000
REQUIRES += arm foc_arndale REQUIRES += arm foc_arndale
SRC_CC += arm/platform_arm.cc SRC_CC += arm/platform_arm.cc
INC_DIR += $(REP_DIR)/src/core/include/arm
vpath platform_services.cc $(GEN_CORE_DIR) vpath platform_services.cc $(GEN_CORE_DIR)

View File

@ -2,7 +2,6 @@ include $(PRG_DIR)/../target.inc
REQUIRES += arm foc_imx53 REQUIRES += arm foc_imx53
SRC_CC += arm/platform_arm.cc SRC_CC += arm/platform_arm.cc
INC_DIR += $(REP_DIR)/src/core/include/arm
LD_TEXT_ADDR = 0x70140000 LD_TEXT_ADDR = 0x70140000

View File

@ -1,29 +0,0 @@
/**
* \brief Base class for shared interrupts on ARM
* \author Sebastian Sumpf
* \date 2012-10-05
*/
/*
* Copyright (C) 2012-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CORE__INCLUDE__ARM__IRQ_PROXY_COMPONENT_H_
#define _CORE__INCLUDE__ARM__IRQ_PROXY_COMPONENT_H_
#include <irq_proxy.h>
namespace Genode {
/**
* On ARM we disable shared interrupts
*/
typedef Irq_proxy_single Irq_proxy_base;
}
#endif /* _CORE__INCLUDE__ARM__IRQ_PROXY_COMPONENT_H_ */

View File

@ -1,78 +0,0 @@
/*
* \brief IRQ session interface for Fiasco.OC
* \author Stefan Kalkowski
* \date 2011-01-28
*/
/*
* Copyright (C) 2011-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_
#define _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_
#include <base/lock.h>
#include <base/semaphore.h>
#include <base/rpc_server.h>
#include <util/list.h>
#include <irq_session/capability.h>
namespace Genode {
class Irq_proxy_component;
class Irq_session_component : public Rpc_object<Irq_session>,
public List<Irq_session_component>::Element
{
private:
/*
* Each IRQ session uses a dedicated server activation
*/
enum { STACK_SIZE = 2048 };
Rpc_entrypoint _ep;
Irq_session_capability _irq_cap;
Irq_proxy_component *_proxy;
public:
/**
* Constructor
*
* \param cap_session capability session to use
* \param irq_alloc platform-dependent IRQ allocator
* \param args session construction arguments
*/
Irq_session_component(Cap_session *cap_session,
Range_allocator *irq_alloc,
const char *args);
/**
* Destructor
*/
~Irq_session_component();
/**
* Return capability to this session
*
* If an initialization error occurs, returned capability is invalid.
*/
Irq_session_capability cap() const { return _irq_cap; }
/***************************
** Irq session interface **
***************************/
void wait_for_irq();
Irq_signal signal();
};
}
#endif /* _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_ */

View File

@ -1,24 +0,0 @@
/**
* \brief Base class for shared interrupts on x86
* \author Sebastian Sumpf
* \date 2012-10-05
*/
/*
* Copyright (C) 2012-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CORE__INCLUDE__X86__IRQ_PROXY_COMPONENT_H_
#define _CORE__INCLUDE__X86__IRQ_PROXY_COMPONENT_H_
#include <irq_proxy.h>
namespace Genode {
typedef Irq_proxy<Thread<1024 * sizeof(addr_t)> > Irq_proxy_base;
}
#endif /* _CORE__INCLUDE__X86__IRQ_PROXY_COMPONENT_H_ */

View File

@ -21,7 +21,6 @@
/* core includes */ /* core includes */
#include <irq_root.h> #include <irq_root.h>
#include <irq_proxy_component.h>
#include <irq_session_component.h> #include <irq_session_component.h>
#include <platform.h> #include <platform.h>
#include <util.h> #include <util.h>
@ -39,6 +38,7 @@ using namespace Genode;
namespace Genode { namespace Genode {
class Interrupt_handler; class Interrupt_handler;
class Irq_proxy_component; class Irq_proxy_component;
typedef Irq_proxy<Thread<1024 * sizeof(addr_t)> > Irq_proxy_base;
} }
/** /**
@ -69,10 +69,10 @@ class Genode::Irq_proxy_component : public Irq_proxy_base
{ {
private: private:
Cap_index *_cap; Cap_index *_cap;
Semaphore _sem; Semaphore _sem;
long _trigger; /* interrupt trigger */ Irq_session::Trigger _trigger; /* interrupt trigger */
long _polarity; /* interrupt polarity */ Irq_session::Polarity _polarity; /* interrupt polarity */
Native_thread _capability() const { return _cap->kcap(); } Native_thread _capability() const { return _cap->kcap(); }
@ -123,107 +123,162 @@ class Genode::Irq_proxy_component : public Irq_proxy_base
: :
Irq_proxy_base(irq_number), Irq_proxy_base(irq_number),
_cap(cap_map()->insert(platform_specific()->cap_id_alloc()->alloc())), _cap(cap_map()->insert(platform_specific()->cap_id_alloc()->alloc())),
_sem(), _trigger(-1), _polarity(-1) { } _sem(), _trigger(Irq_session::TRIGGER_UNCHANGED),
_polarity(Irq_session::POLARITY_UNCHANGED)
Semaphore *semaphore() { return &_sem; }
void start(long trigger, long polarity)
{ {
_trigger = trigger;
_polarity = polarity;
_start(); _start();
} }
bool match_mode(long trigger, long polarity) Semaphore *semaphore() { return &_sem; }
Irq_session::Trigger trigger() const { return _trigger; }
Irq_session::Polarity polarity() const { return _polarity; }
void setup_irq_mode(Irq_session::Trigger t, Irq_session::Polarity p)
{ {
if (trigger == Irq_session::TRIGGER_UNCHANGED && _trigger = t;
polarity == Irq_session::POLARITY_UNCHANGED) _polarity = p;
return true;
if (_trigger < 0 && _polarity < 0) /* set interrupt mode */
return true; Platform::setup_irq_mode(_irq_number, _trigger, _polarity);
return _trigger == trigger && _polarity == polarity;
} }
long trigger() const { return _trigger; }
long polarity() const { return _polarity; }
}; };
/******************************** /***************************
** IRQ session implementation ** ** IRQ session component **
********************************/ ***************************/
Irq_session_component::Irq_session_component(Cap_session *cap_session, void Irq_session_component::ack_irq()
Range_allocator *irq_alloc,
const char *args)
:
_ep(cap_session, STACK_SIZE, "irqctrl"),
_proxy(0)
{ {
using namespace Fiasco; if (!_proxy) {
PERR("Expected to find IRQ proxy for IRQ %02x", _irq_number);
long irq_number = Arg_string::find_arg(args, "irq_number").long_value(-1); return;
if (irq_number == -1) {
PERR("Unavailable IRQ %lx requested", irq_number);
throw Root::Invalid_args();
} }
long irq_trigger = Arg_string::find_arg(args, "irq_trigger").long_value(-1); _proxy->ack_irq();
irq_trigger = irq_trigger == -1 ? 0 : irq_trigger; }
long irq_polarity = Arg_string::find_arg(args, "irq_polarity").long_value(-1);
irq_polarity = irq_polarity == -1 ? 0 : irq_polarity; Irq_session_component::Irq_session_component(Range_allocator *irq_alloc,
const char *args)
{
long irq_number = Arg_string::find_arg(args, "irq_number").long_value(-1);
if (irq_number == -1) {
PERR("invalid IRQ number requested");
throw Root::Unavailable();
}
long irq_t = Arg_string::find_arg(args, "irq_trigger").long_value(-1);
long irq_p = Arg_string::find_arg(args, "irq_polarity").long_value(-1);
Irq_session::Trigger irq_trigger;
Irq_session::Polarity irq_polarity;
switch(irq_t) {
case -1:
case Irq_session::TRIGGER_UNCHANGED:
irq_trigger = Irq_session::TRIGGER_UNCHANGED;
break;
case Irq_session::TRIGGER_EDGE:
irq_trigger = Irq_session::TRIGGER_EDGE;
break;
case Irq_session::TRIGGER_LEVEL:
irq_trigger = Irq_session::TRIGGER_LEVEL;
break;
default:
throw Root::Unavailable();
}
switch(irq_p) {
case -1:
case POLARITY_UNCHANGED:
irq_polarity = POLARITY_UNCHANGED;
break;
case POLARITY_HIGH:
irq_polarity = POLARITY_HIGH;
break;
case POLARITY_LOW:
irq_polarity = POLARITY_LOW;
break;
default:
throw Root::Unavailable();
}
/* /*
* temorary hack for fiasco.oc using the local-apic, * temporary hack for fiasco.oc using the local-apic,
* where old pic-line 0 maps to 2 * where old pic-line 0 maps to 2
*/ */
if (irq_number == 0) if (irq_number == 0)
irq_number = 2; irq_number = 2;
if (!(_proxy = Irq_proxy_component::get_irq_proxy<Irq_proxy_component>(irq_number, /* check if IRQ thread was started before */
irq_alloc))) { _proxy = Irq_proxy_component::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc);
PERR("No proxy for IRQ %lu found", irq_number); if (!_proxy) {
PERR("unavailable IRQ %lx requested", irq_number);
throw Root::Unavailable(); throw Root::Unavailable();
} }
bool setup = false;
bool fail = false;
/* sanity check */ /* sanity check */
if (!_proxy->match_mode(irq_trigger, irq_polarity)) { if (irq_trigger != TRIGGER_UNCHANGED && _proxy->trigger() != irq_trigger) {
PERR("Interrupt mode mismatch: IRQ %ld current mode: t: %ld p: %ld" if (_proxy->trigger() == TRIGGER_UNCHANGED)
"request mode: trg: %ld p: %ld", setup = true;
else
fail = true;
}
if (irq_polarity != POLARITY_UNCHANGED && _proxy->polarity() != irq_polarity) {
if (_proxy->polarity() == POLARITY_UNCHANGED)
setup = true;
else
fail = true;
}
if (fail) {
PERR("Interrupt mode mismatch: IRQ %ld current mode: t: %d p: %d "
"request mode: trg: %d p: %d",
irq_number, _proxy->trigger(), _proxy->polarity(), irq_number, _proxy->trigger(), _proxy->polarity(),
irq_trigger, irq_polarity); irq_trigger, irq_polarity);
throw Root::Unavailable(); throw Root::Unavailable();
} }
/* set interrupt mode and start proxy */ if (setup)
_proxy->start(irq_trigger, irq_polarity); /* set interrupt mode */
_proxy->setup_irq_mode(irq_trigger, irq_polarity);
if (!_proxy->add_sharer()) _irq_number = irq_number;
throw Root::Unavailable();
/* initialize capability */
_irq_cap = _ep.manage(this);
} }
void Irq_session_component::wait_for_irq() Irq_session_component::~Irq_session_component()
{ {
_proxy->wait_for_irq(); if (!_proxy) return;
if (_irq_sigh.valid())
_proxy->remove_sharer(&_irq_sigh);
} }
Irq_session_component::~Irq_session_component() { void Irq_session_component::sigh(Genode::Signal_context_capability sigh)
_proxy->remove_sharer(); }
Irq_signal Irq_session_component::signal()
{ {
PDBG("not implemented;"); if (!_proxy) {
return Irq_signal(); PERR("signal handler got not registered - irq thread unavailable");
return;
}
Genode::Signal_context_capability old = _irq_sigh;
if (old.valid() && !sigh.valid())
_proxy->remove_sharer(&_irq_sigh);
_irq_sigh = sigh;
if (!old.valid() && sigh.valid())
_proxy->add_sharer(&_irq_sigh);
} }

View File

@ -4,6 +4,5 @@ LD_TEXT_ADDR = 0x80140000
REQUIRES += arm foc_panda REQUIRES += arm foc_panda
SRC_CC += arm/platform_arm.cc SRC_CC += arm/platform_arm.cc
INC_DIR += $(REP_DIR)/src/core/include/arm
vpath platform_services.cc $(GEN_CORE_DIR) vpath platform_services.cc $(GEN_CORE_DIR)

View File

@ -2,7 +2,6 @@ include $(PRG_DIR)/../target.inc
REQUIRES += arm foc_pbxa9 REQUIRES += arm foc_pbxa9
SRC_CC += arm/platform_arm.cc SRC_CC += arm/platform_arm.cc
INC_DIR += $(REP_DIR)/src/core/include/arm
LD_TEXT_ADDR = 0x70490000 LD_TEXT_ADDR = 0x70490000

View File

@ -2,7 +2,6 @@ include $(PRG_DIR)/../target.inc
REQUIRES += arm foc_vea9x4 REQUIRES += arm foc_vea9x4
SRC_CC += arm/platform_arm.cc SRC_CC += arm/platform_arm.cc
INC_DIR += $(REP_DIR)/src/core/include/arm
LD_TEXT_ADDR = 0x60490000 LD_TEXT_ADDR = 0x60490000

View File

@ -5,7 +5,5 @@ REQUIRES += x86
SRC_CC += io_port_session_component.cc \ SRC_CC += io_port_session_component.cc \
x86/platform_x86.cc x86/platform_x86.cc
INC_DIR += $(REP_DIR)/src/core/include/x86
vpath io_port_session_component.cc $(GEN_CORE_DIR)/x86 vpath io_port_session_component.cc $(GEN_CORE_DIR)/x86
vpath platform_services.cc $(GEN_CORE_DIR)/x86 vpath platform_services.cc $(GEN_CORE_DIR)/x86

View File

@ -207,12 +207,10 @@ namespace Kernel
* Await any context of a receiver and optionally ack a context before * Await any context of a receiver and optionally ack a context before
* *
* \param receiver_id kernel name of the targeted signal receiver * \param receiver_id kernel name of the targeted signal receiver
* \param context_id kernel name of a context that shall be acknowledged
* *
* \retval 0 suceeded * \retval 0 suceeded
* \retval -1 failed * \retval -1 failed
* *
* If context is set to 0, the call doesn't acknowledge any context.
* If this call returns 0, an instance of 'Signal::Data' is located at the * If this call returns 0, an instance of 'Signal::Data' is located at the
* base of the callers UTCB. Every occurence of a signal is provided * base of the callers UTCB. Every occurence of a signal is provided
* through this function until it gets delivered through this function or * through this function until it gets delivered through this function or
@ -223,10 +221,9 @@ namespace Kernel
* deliver again unless its last delivery has been acknowledged via * deliver again unless its last delivery has been acknowledged via
* ack_signal. * ack_signal.
*/ */
inline int await_signal(unsigned const receiver_id, inline int await_signal(unsigned const receiver_id)
unsigned const context_id)
{ {
return call(call_id_await_signal(), receiver_id, context_id); return call(call_id_await_signal(), receiver_id);
} }

View File

@ -1,23 +0,0 @@
/*
* \brief Client-side IRQ session interface - specific for base-hw
* \author Martin Stein
* \date 2013-10-24
*/
/*
* Copyright (C) 2013-2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <irq_session/client.h>
void Genode::Irq_session_client::wait_for_irq()
{
while (Kernel::await_signal(irq_signal.receiver_id,
irq_signal.context_id))
{
PERR("failed to receive interrupt");
}
}

View File

@ -189,7 +189,7 @@ bool Signal_receiver::pending() { return Kernel::signal_pending(_cap.dst()); }
Signal Signal_receiver::wait_for_signal() Signal Signal_receiver::wait_for_signal()
{ {
/* await a signal */ /* await a signal */
if (Kernel::await_signal(_cap.dst(), 0)) { if (Kernel::await_signal(_cap.dst())) {
PERR("failed to receive signal"); PERR("failed to receive signal");
return Signal(Signal::Data()); return Signal(Signal::Data());
} }

View File

@ -5,71 +5,59 @@
*/ */
/* /*
* Copyright (C) 2013 Genode Labs GmbH * Copyright (C) 2013-2015 Genode Labs GmbH
* *
* This file is part of the Genode OS framework, which is distributed * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
*/ */
#ifndef _INCLUDE__IRQ_SESSION_COMPONENT_H_ #ifndef _INCLUDE__IRQ_SESSION_COMPONENT_H_
#define _INCLUDE__IRQ_SESSION_COMPONENT_H_ #define __INCLUDE__IRQ_SESSION_COMPONENT_H_
/* Genode includes */ /* Genode includes */
#include <base/rpc_server.h> #include <base/rpc_server.h>
#include <util/list.h> #include <util/list.h>
#include <irq_session/capability.h> #include <irq_session/capability.h>
namespace Genode namespace Genode {
{ class Irq_session_component;
/**
* Backend for IRQ sessions to core
*/
class Irq_session_component
:
public Rpc_object<Irq_session, Irq_session_component>,
public List<Irq_session_component>::Element
{
private:
Range_allocator * const _irq_alloc;
Irq_session_capability _cap;
Irq_signal _signal;
Genode::uint8_t _kernel_object[sizeof(Kernel::User_irq)];
public:
/**
* Constructor
*
* \param cap_session capability session to use
* \param irq_alloc interrupt allocator
* \param args session construction arguments
*/
Irq_session_component(Cap_session * const cap_session,
Range_allocator * const irq_alloc,
const char * const args);
/**
* Destructor
*/
~Irq_session_component();
/**
* Return capability to this session
*
* If an initialization error occurs, returned _cap is invalid.
*/
Irq_session_capability cap() const { return _cap; }
/*****************
** Irq_session **
*****************/
void wait_for_irq();
Irq_signal signal();
};
} }
class Genode::Irq_session_component : public Rpc_object<Irq_session>,
public List<Irq_session_component>::Element
{
private:
unsigned _irq_number;
Range_allocator *_irq_alloc;
Genode::uint8_t _kernel_object[sizeof(Kernel::User_irq)];
Signal_context_capability _sig_cap;
unsigned _find_irq_number(const char * const args);
public:
/**
* Constructor
*
* \param irq_alloc platform-dependent IRQ allocator
* \param args session construction arguments
*/
Irq_session_component(Range_allocator *irq_alloc,
const char *args);
/**
* Destructor
*/
~Irq_session_component();
/***************************
** Irq session interface **
***************************/
void ack_irq();
void sigh(Signal_context_capability) override;
};
#endif /* _INCLUDE__IRQ_SESSION_COMPONENT_H_ */ #endif /* _INCLUDE__IRQ_SESSION_COMPONENT_H_ */

View File

@ -353,12 +353,14 @@ namespace Kernel
/** /**
* Create an interrupt object * Create an interrupt object
* *
* \param p memory donation for the irq object * \param p memory donation for the irq object
* \param irq_nr interrupt number * \param irq_nr interrupt number
* \param signal_context_id kernel name of the signal context
*/ */
inline void new_irq(addr_t const p, unsigned irq_nr) inline int new_irq(addr_t const p, unsigned irq_nr,
unsigned signal_context_id)
{ {
call(call_id_new_irq(), (Call_arg) p, irq_nr); return call(call_id_new_irq(), (Call_arg) p, irq_nr, signal_context_id);
} }
/** /**

View File

@ -47,8 +47,14 @@ namespace Genode
class Kernel::Irq : public Object_pool<Irq>::Item class Kernel::Irq : public Object_pool<Irq>::Item
{ {
public:
using Pool = Object_pool<Irq>;
protected: protected:
Pool &_pool;
/** /**
* Get kernel name of the interrupt * Get kernel name of the interrupt
*/ */
@ -56,16 +62,6 @@ class Kernel::Irq : public Object_pool<Irq>::Item
public: public:
using Pool = Object_pool<Irq>;
/**
* Constructor
*
* \param irq_id kernel name of the interrupt
*/
Irq(unsigned const irq_id)
: Pool::Item(irq_id) { }
/** /**
* Constructor * Constructor
* *
@ -73,14 +69,9 @@ class Kernel::Irq : public Object_pool<Irq>::Item
* \param pool pool this interrupt shall belong to * \param pool pool this interrupt shall belong to
*/ */
Irq(unsigned const irq_id, Pool &pool) Irq(unsigned const irq_id, Pool &pool)
: Irq(irq_id) { pool.insert(this); } : Pool::Item(irq_id), _pool(pool) { _pool.insert(this); }
/** virtual ~Irq() { _pool.remove(this); }
* Destructor
*
* By now, there is no use case to destruct interrupts
*/
virtual ~Irq() { PERR("destruction of interrupts not implemented"); }
/** /**
* Handle occurence of the interrupt * Handle occurence of the interrupt
@ -102,12 +93,12 @@ class Kernel::Irq : public Object_pool<Irq>::Item
class Kernel::User_irq class Kernel::User_irq
: :
public Kernel::Irq, public Kernel::Irq,
public Signal_receiver,
public Signal_context,
public Signal_ack_handler public Signal_ack_handler
{ {
private: private:
Signal_context &_context;
/** /**
* Get map that provides all user interrupts by their kernel names * Get map that provides all user interrupts by their kernel names
*/ */
@ -127,30 +118,25 @@ class Kernel::User_irq
* *
* \param irq_id kernel name of the interrupt * \param irq_id kernel name of the interrupt
*/ */
User_irq(unsigned const irq_id) User_irq(unsigned const irq_id, Signal_context &context)
: Irq(irq_id), Signal_context(this, 0) : Irq(irq_id, *_pool()), _context(context)
{ {
_pool()->insert(this);
disable(); disable();
Signal_context::ack_handler(this); _context.ack_handler(this);
} }
/** ~User_irq()
* Get kernel name of the interrupt-signal receiver {
*/ _context.ack_handler(nullptr);
unsigned receiver_id() const { return Signal_receiver::Object::id(); } disable();
}
/**
* Get kernel name of the interrupt-signal context
*/
unsigned context_id() const { return Signal_context::Object::id(); }
/** /**
* Handle occurence of the interrupt * Handle occurence of the interrupt
*/ */
void occurred() void occurred()
{ {
Signal_context::submit(1); _context.submit(1);
disable(); disable();
} }

View File

@ -22,64 +22,53 @@
using namespace Genode; using namespace Genode;
/**
* On other platforms, every IRQ session component creates its entrypoint. unsigned Irq_session_component::_find_irq_number(const char * const args)
* However, on base-hw this isn't necessary as users can wait for their
* interrupts directly. Instead of replacing cores generic irq_root.h and
* main.cc with base-hw specific versions, we simply use a local singleton.h
*/
static Rpc_entrypoint * irq_session_ep()
{ {
enum { STACK_SIZE = 2048 }; return Arg_string::find_arg(args, "irq_number").long_value(-1);
static Rpc_entrypoint
_ep(core_env()->cap_session(), STACK_SIZE, "irq_session_ep");
return &_ep;
} }
void Irq_session_component::wait_for_irq() { PERR("not implemented"); }
Irq_signal Irq_session_component::signal() { return _signal; } void Irq_session_component::ack_irq()
{
Kernel::ack_signal(_sig_cap.dst());
}
void Irq_session_component::sigh(Signal_context_capability cap)
{
if (_sig_cap.valid()) {
PWRN("signal handler already registered for IRQ %u", _irq_number);
return;
}
_sig_cap = cap;
if (Kernel::new_irq((addr_t)&_kernel_object, _irq_number, _sig_cap.dst()))
PWRN("invalid signal handler for IRQ %u", _irq_number);
}
Irq_session_component::~Irq_session_component() Irq_session_component::~Irq_session_component()
{ {
using namespace Kernel; using namespace Kernel;
irq_session_ep()->dissolve(this);
User_irq * kirq = reinterpret_cast<User_irq*>(&_kernel_object); User_irq * kirq = reinterpret_cast<User_irq*>(&_kernel_object);
_irq_alloc->free((void *)(addr_t)static_cast<Kernel::Irq*>(kirq)->id()); _irq_alloc->free((void *)(addr_t)static_cast<Kernel::Irq*>(kirq)->id());
Kernel::delete_irq(kirq); if (_sig_cap.valid())
Kernel::delete_irq(kirq);
} }
Irq_session_component::Irq_session_component(Cap_session * const cap_session,
Range_allocator * const irq_alloc, Irq_session_component::Irq_session_component(Range_allocator * const irq_alloc,
const char * const args) const char * const args)
: _irq_alloc(irq_alloc) :
_irq_number(Platform::irq(_find_irq_number(args))),
_irq_alloc(irq_alloc)
{ {
using namespace Kernel;
/* check arguments */
bool shared = Arg_string::find_arg(args, "irq_shared").bool_value(false);
if (shared) {
PERR("shared interrupts not supported");
throw Root::Invalid_args();
}
/* allocate interrupt */ /* allocate interrupt */
long irq_nr = Arg_string::find_arg(args, "irq_number").long_value(-1); if (_irq_alloc->alloc_addr(1, _irq_number).is_error()) {
bool error = irq_nr < 0 || !_irq_alloc;
/* enable platform specific code to apply mappings */
long const plat_irq_nr = Platform::irq(irq_nr);
error |= _irq_alloc->alloc_addr(1, plat_irq_nr).is_error();
if (error) {
PERR("unavailable interrupt requested"); PERR("unavailable interrupt requested");
throw Root::Invalid_args(); throw Root::Invalid_args();
} }
/* make interrupt accessible */
new_irq((addr_t)&_kernel_object, plat_irq_nr);
User_irq * kirq = reinterpret_cast<User_irq*>(&_kernel_object);
_signal = { kirq->receiver_id(), kirq->context_id() };
_cap = Irq_session_capability(irq_session_ep()->manage(this));
} }

View File

@ -582,13 +582,6 @@ void Thread::_call_new_signal_context()
void Thread::_call_await_signal() void Thread::_call_await_signal()
{ {
/* check wether to acknowledge a context */
unsigned const context_id = user_arg_2();
if (context_id) {
Signal_context * const c = Signal_context::pool()->object(context_id);
if (c) { c->ack(); }
else { PWRN("failed to acknowledge signal context"); }
}
/* lookup receiver */ /* lookup receiver */
unsigned const receiver_id = user_arg_1(); unsigned const receiver_id = user_arg_1();
Signal_receiver * const r = Signal_receiver::pool()->object(receiver_id); Signal_receiver * const r = Signal_receiver::pool()->object(receiver_id);
@ -688,8 +681,19 @@ void Thread::_call_delete_signal_receiver() {
reinterpret_cast<Signal_receiver*>(user_arg_1())->~Signal_receiver(); } reinterpret_cast<Signal_receiver*>(user_arg_1())->~Signal_receiver(); }
void Thread::_call_new_irq() { void Thread::_call_new_irq()
new ((void *)user_arg_1()) User_irq(user_arg_2()); } {
Signal_context * const c = Signal_context::pool()->object(user_arg_3());
if (!c) {
PWRN("%s -> %s: invalid signal context for interrupt",
pd_label(), label());
user_arg_0(-1);
return;
}
new ((void *)user_arg_1()) User_irq(user_arg_2(), *c);
user_arg_0(0);
}
void Thread::_call_delete_irq() { void Thread::_call_delete_irq() {

View File

@ -49,7 +49,7 @@ extern Genode::addr_t _vt_host_context_ptr;
struct Kernel::Vm_irq : Kernel::Irq struct Kernel::Vm_irq : Kernel::Irq
{ {
Vm_irq(unsigned const irq) : Kernel::Irq(irq) {} Vm_irq(unsigned const irq) : Kernel::Irq(irq, *cpu_pool()->executing_cpu()) {}
/** /**
* A VM interrupt gets injected into the VM scheduled on the current CPU * A VM interrupt gets injected into the VM scheduled on the current CPU
@ -180,10 +180,6 @@ struct Kernel::Virtual_timer
void Kernel::prepare_hypervisor() void Kernel::prepare_hypervisor()
{ {
Cpu * cpu = cpu_pool()->executing_cpu();
cpu->insert(&Virtual_timer::timer().irq);
cpu->insert(&Virtual_pic::pic().irq);
/* set hypervisor exception vector */ /* set hypervisor exception vector */
Cpu::hyp_exception_entry_at(&_vt_host_entry); Cpu::hyp_exception_entry_at(&_vt_host_entry);

View File

@ -20,6 +20,7 @@ SRC_CC += env/rm_session_mmap.cc env/debug.cc
SRC_CC += signal/signal.cc signal/common.cc signal/platform.cc SRC_CC += signal/signal.cc signal/common.cc signal/platform.cc
SRC_CC += server/server.cc server/common.cc SRC_CC += server/server.cc server/common.cc
SRC_CC += thread/trace.cc thread/thread_env.cc thread/context_allocator.cc SRC_CC += thread/trace.cc thread/thread_env.cc thread/context_allocator.cc
SRC_CC += irq/platform.cc
INC_DIR += $(REP_DIR)/src/base/lock $(BASE_DIR)/src/base/lock INC_DIR += $(REP_DIR)/src/base/lock $(BASE_DIR)/src/base/lock
INC_DIR += $(REP_DIR)/src/base/ipc INC_DIR += $(REP_DIR)/src/base/ipc

View File

@ -15,46 +15,38 @@
#define _CORE__INCLUDE__LINUX__IRQ_SESSION_COMPONENT_H_ #define _CORE__INCLUDE__LINUX__IRQ_SESSION_COMPONENT_H_
#include <util/list.h> #include <util/list.h>
#include <base/lock.h>
#include <base/rpc_server.h> #include <base/rpc_server.h>
#include <irq_session/irq_session.h> #include <irq_session/irq_session.h>
namespace Genode { namespace Genode {
class Irq_session_component;
class Irq_session_component : public List<Irq_session_component>::Element
{
public:
/**
* Constructor
*
* \param cap_session capability session to use
* \param irq_alloc platform-dependent IRQ allocator
* \param args session construction arguments
*/
Irq_session_component(Cap_session *cap_session,
Range_allocator *irq_alloc,
const char *args) { }
/**
* Destructor
*/
~Irq_session_component() { }
/**
* Return capability to this session
*
* Capability is always invalid under Linux.
*/
Session_capability cap() const { return Session_capability(); }
/***************************
** Irq session interface **
***************************/
void wait_for_irq() { }
};
} }
class Genode::Irq_session_component : public Rpc_object<Irq_session>,
public List<Irq_session_component>::Element
{
public:
/**
* Constructor
*
* \param irq_alloc platform-dependent IRQ allocator
* \param args session construction arguments
*/
Irq_session_component(Range_allocator *irq_alloc,
const char *args) { }
/**
* Destructor
*/
~Irq_session_component() { }
/***************************
** Irq session interface **
***************************/
void ack_irq() { }
void sigh(Signal_context_capability) override { }
};
#endif /* _CORE__INCLUDE__LINUX__IRQ_SESSION_COMPONENT_H_ */ #endif /* _CORE__INCLUDE__LINUX__IRQ_SESSION_COMPONENT_H_ */

View File

@ -1,75 +0,0 @@
/*
* \brief IRQ session interface for NOVA
* \author Norman Feske
* \date 2010-01-30
*/
/*
* Copyright (C) 2010-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_
#define _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_
#include <base/lock.h>
#include <base/rpc_server.h>
#include <util/list.h>
#include <irq_session/capability.h>
namespace Genode {
class Irq_proxy_component;
class Irq_session_component : public Rpc_object<Irq_session>,
public List<Irq_session_component>::Element
{
private:
/*
* Each IRQ session uses a dedicated server activation
*/
enum { STACK_SIZE = 2048 };
Rpc_entrypoint _ep;
Irq_session_capability _irq_cap;
Irq_proxy_component *_proxy;
public:
/**
* Constructor
*
* \param cap_session capability session to use
* \param irq_alloc platform-dependent IRQ allocator
* \param args session construction arguments
*/
Irq_session_component(Cap_session *cap_session,
Range_allocator *irq_alloc,
const char *args);
/**
* Destructor
*/
~Irq_session_component();
/**
* Return capability to this session
*
* If an initialization error occurs, returned capability is invalid.
*/
Irq_session_capability cap() const { return _irq_cap; }
/***************************
** Irq session interface **
***************************/
void wait_for_irq();
Irq_signal signal();
};
}
#endif /* _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_ */

View File

@ -170,43 +170,68 @@ class Genode::Irq_proxy_component : public Irq_proxy<Irq_thread>
}; };
typedef Irq_proxy<Irq_thread> Proxy;
void Irq_session_component::wait_for_irq() /***************************
** IRQ session component **
***************************/
void Irq_session_component::ack_irq()
{ {
_proxy->wait_for_irq(); if (!_proxy) {
/* interrupt ocurred and proxy woke us up */ PERR("Expected to find IRQ proxy for IRQ %02x", _irq_number);
return;
}
_proxy->ack_irq();
} }
Irq_session_component::Irq_session_component(Cap_session *cap_session, Irq_session_component::Irq_session_component(Range_allocator *irq_alloc,
Range_allocator *irq_alloc,
const char *args) const char *args)
:
_ep(cap_session, STACK_SIZE, "irq")
{ {
long irq_number = Arg_string::find_arg(args, "irq_number").long_value(-1); long irq_number = Arg_string::find_arg(args, "irq_number").long_value(-1);
if (irq_number == -1) {
/* check if IRQ thread was started before */ PERR("invalid IRQ number requested");
_proxy = Proxy::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc);
if (irq_number == -1 || !_proxy) {
PERR("Unavailable IRQ %lx requested", irq_number);
throw Root::Unavailable(); throw Root::Unavailable();
} }
_proxy->add_sharer(); /* check if IRQ thread was started before */
typedef Irq_proxy<Irq_thread> Proxy;
_proxy = Proxy::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc);
if (!_proxy) {
PERR("unavailable IRQ %lx requested", irq_number);
throw Root::Unavailable();
}
/* initialize capability */ _irq_number = irq_number;
_irq_cap = _ep.manage(this);
} }
Irq_session_component::~Irq_session_component() { } Irq_session_component::~Irq_session_component()
Irq_signal Irq_session_component::signal()
{ {
PDBG("not implemented;"); if (_proxy) return;
return Irq_signal();
if (_irq_sigh.valid())
_proxy->remove_sharer(&_irq_sigh);
}
void Irq_session_component::sigh(Genode::Signal_context_capability sigh)
{
if (!_proxy) {
PERR("signal handler got not registered - irq thread unavailable");
return;
}
Genode::Signal_context_capability old = _irq_sigh;
if (old.valid() && !sigh.valid())
_proxy->remove_sharer(&_irq_sigh);
_irq_sigh = sigh;
if (!old.valid() && sigh.valid())
_proxy->add_sharer(&_irq_sigh);
} }

View File

@ -12,10 +12,12 @@
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
*/ */
#include <irq_proxy.h> /* Genode includes */
#include <base/printf.h>
#include <util/arg_string.h>
/* core includes */ /* core includes */
#include <irq_root.h> #include <irq_session_component.h>
/* OKL4 includes */ /* OKL4 includes */
namespace Okl4 { extern "C" { namespace Okl4 { extern "C" {
@ -30,12 +32,6 @@ using namespace Okl4;
using namespace Genode; using namespace Genode;
/**
* Proxy class with generic thread
*/
typedef Irq_proxy<Thread<0x1000> > Proxy;
/* XXX move this functionality to a central place instead of duplicating it */ /* XXX move this functionality to a central place instead of duplicating it */
static inline Okl4::L4_ThreadId_t thread_get_my_global_id() static inline Okl4::L4_ThreadId_t thread_get_my_global_id()
{ {
@ -44,11 +40,15 @@ static inline Okl4::L4_ThreadId_t thread_get_my_global_id()
return myself; return myself;
} }
namespace Genode {
typedef Irq_proxy<Thread<1024 * sizeof(addr_t)> > Irq_proxy_base;
class Irq_proxy_component;
}
/** /**
* Platform-specific proxy code * Platform-specific proxy code
*/ */
class Irq_proxy_component : public Proxy class Genode::Irq_proxy_component : public Irq_proxy_base
{ {
protected: protected:
@ -80,13 +80,14 @@ class Irq_proxy_component : public Proxy
/* prepare ourself to receive asynchronous IRQ notifications */ /* prepare ourself to receive asynchronous IRQ notifications */
L4_Set_NotifyMask(1 << IRQ_NOTIFY_BIT); L4_Set_NotifyMask(1 << IRQ_NOTIFY_BIT);
L4_Accept(L4_NotifyMsgAcceptor);
return true; return true;
} }
void _wait_for_irq() void _wait_for_irq()
{ {
L4_Accept(L4_NotifyMsgAcceptor);
/* wait for asynchronous interrupt notification */ /* wait for asynchronous interrupt notification */
L4_ThreadId_t partner = L4_nilthread; L4_ThreadId_t partner = L4_nilthread;
L4_ReplyWait(partner, &partner); L4_ReplyWait(partner, &partner);
@ -111,35 +112,23 @@ class Irq_proxy_component : public Proxy
** IRQ session component ** ** IRQ session component **
***************************/ ***************************/
bool Irq_session_component::Irq_control_component::associate_to_irq(unsigned irq)
{
return true;
}
void Irq_session_component::ack_irq()
void Irq_session_component::wait_for_irq()
{ {
/* block at interrupt proxy */ /* block at interrupt proxy */
Proxy *p = Proxy::get_irq_proxy<Irq_proxy_component>(_irq_number); if (!_proxy) {
if (!p) {
PERR("Expected to find IRQ proxy for IRQ %02x", _irq_number); PERR("Expected to find IRQ proxy for IRQ %02x", _irq_number);
return; return;
} }
p->wait_for_irq(); _proxy->ack_irq();
/* interrupt ocurred and proxy woke us up */
} }
Irq_session_component::Irq_session_component(Cap_session *cap_session, Irq_session_component::Irq_session_component(Range_allocator *irq_alloc,
Range_allocator *irq_alloc,
const char *args) const char *args)
: :
_irq_alloc(irq_alloc), _irq_alloc(irq_alloc)
_ep(cap_session, STACK_SIZE, "irqctrl"),
_irq_attached(false),
_control_client(Capability<Irq_session_component::Irq_control>())
{ {
/* /*
* XXX Removed irq_shared argument as this is the default now. If we need * XXX Removed irq_shared argument as this is the default now. If we need
@ -154,30 +143,39 @@ Irq_session_component::Irq_session_component(Cap_session *cap_session,
} }
/* check if IRQ thread was started before */ /* check if IRQ thread was started before */
Proxy *irq_proxy = Proxy::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc); _proxy = Irq_proxy_component::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc);
if (!irq_proxy) { if (!_proxy) {
PERR("unavailable IRQ %lx requested", irq_number); PERR("unavailable IRQ %lx requested", irq_number);
throw Root::Unavailable(); throw Root::Unavailable();
} }
irq_proxy->add_sharer();
_irq_number = irq_number; _irq_number = irq_number;
/* initialize capability */
_irq_cap = _ep.manage(this);
} }
Irq_session_component::~Irq_session_component() Irq_session_component::~Irq_session_component()
{ {
PERR("not yet implemented"); if (!_proxy) return;
/* TODO del_sharer() resp. put_sharer() */
if (_irq_sigh.valid())
_proxy->remove_sharer(&_irq_sigh);
} }
Irq_signal Irq_session_component::signal() void Irq_session_component::sigh(Genode::Signal_context_capability sigh)
{ {
PDBG("not implemented;"); if (!_proxy) {
return Irq_signal(); PERR("signal handler got not registered - irq thread unavailable");
return;
}
Genode::Signal_context_capability old = _irq_sigh;
if (old.valid() && !sigh.valid())
_proxy->remove_sharer(&_irq_sigh);
_irq_sigh = sigh;
if (!old.valid() && sigh.valid())
_proxy->add_sharer(&_irq_sigh);
} }

View File

@ -18,6 +18,7 @@
#include <util/arg_string.h> #include <util/arg_string.h>
/* core includes */ /* core includes */
#include <irq_proxy.h>
#include <irq_root.h> #include <irq_root.h>
#include <util.h> #include <util.h>
@ -39,102 +40,161 @@ static inline L4_ThreadId_t irqno_to_threadid(unsigned int irqno)
} }
bool Irq_session_component::Irq_control_component::associate_to_irq(unsigned) namespace Genode {
{ typedef Irq_proxy<Thread<1024 * sizeof(addr_t)> > Irq_proxy_base;
/* class Irq_proxy_component;
* We defer the association with the IRQ to the first call of the
* 'wait_for_irq' function.
*/
return true;
} }
void Irq_session_component::wait_for_irq() /**
* Platform-specific proxy code
*/
class Genode::Irq_proxy_component : public Irq_proxy_base
{ {
L4_ThreadId_t irq_thread = irqno_to_threadid(_irq_number); private:
/* attach to IRQ when called for the first time */ /*
L4_MsgTag_t res; * On Pistachio, an IRQ is unmasked right after attaching.
if (!_irq_attached) { * Hence, the kernel may send an IRQ IPC when the IRQ hander is
* not explicitly waiting for an IRQ but when it is waiting for
* a client's 'wait_for_irq' RPC call. To avoid this conflict, we
* lazily associate to the IRQ when calling the 'wait_for_irq'
* function for the first time. We use the '_irq_attached' flag
* for detecting the first call.
*/
bool _irq_attached; /* true if IRQ is already attached */
if (L4_AssociateInterrupt(irq_thread, L4_Myself()) != true) { protected:
PERR("L4_AssociateInterrupt failed");
return; bool _associate() { return true; }
void _wait_for_irq()
{
L4_ThreadId_t irq_thread = irqno_to_threadid(_irq_number);
/* attach to IRQ when called for the first time */
L4_MsgTag_t res;
if (!_irq_attached) {
if (L4_AssociateInterrupt(irq_thread, L4_Myself()) != true) {
PERR("L4_AssociateInterrupt failed");
return;
}
/*
* Right after associating with an interrupt, the interrupt is
* unmasked. Hence, we do not need to send an unmask message
* to the IRQ thread but just wait for the IRQ.
*/
L4_Set_MsgTag(L4_Niltag);
res = L4_Receive(irq_thread);
/*
* Now, the IRQ is masked. To receive the next IRQ we have to send
* an unmask message to the IRQ thread first.
*/
_irq_attached = true;
/* receive subsequent interrupt */
} else {
/* send unmask message and wait for new IRQ */
L4_Set_MsgTag(L4_Niltag);
res = L4_Call(irq_thread);
}
if (L4_IpcFailed(res)) {
PERR("ipc error while waiting for interrupt.");
return;
}
} }
/* void _ack_irq() { }
* Right after associating with an interrupt, the interrupt is
* unmasked. Hence, we do not need to send an unmask message
* to the IRQ thread but just wait for the IRQ.
*/
L4_Set_MsgTag(L4_Niltag);
res = L4_Receive(irq_thread);
/* public:
* Now, the IRQ is masked. To receive the next IRQ we have to send
* an unmask message to the IRQ thread first.
*/
_irq_attached = true;
/* receive subsequent interrupt */ Irq_proxy_component(long irq_number)
} else { :
Irq_proxy(irq_number),
_irq_attached(false)
{
_start();
}
/* send unmask message and wait for new IRQ */ ~Irq_proxy_component()
L4_Set_MsgTag(L4_Niltag); {
res = L4_Call(irq_thread); L4_ThreadId_t const thread_id = irqno_to_threadid(_irq_number);
} L4_Word_t const res = L4_DeassociateInterrupt(thread_id);
if (L4_IpcFailed(res)) { if (res != 1)
PERR("ipc error while waiting for interrupt."); PERR("L4_DeassociateInterrupt failed");
}
};
/***************************
** IRQ session component **
***************************/
void Irq_session_component::ack_irq()
{
if (!_proxy) {
PERR("Expected to find IRQ proxy for IRQ %02x", _irq_number);
return; return;
} }
_proxy->ack_irq();
} }
Irq_session_component::Irq_session_component(Cap_session *cap_session, Irq_session_component::Irq_session_component(Range_allocator *irq_alloc,
Range_allocator *irq_alloc,
const char *args) const char *args)
: :
_irq_alloc(irq_alloc), _irq_alloc(irq_alloc)
_ep(cap_session, STACK_SIZE, "irqctrl"),
_irq_attached(false),
_control_client(Capability<Irq_session_component::Irq_control>())
{ {
bool shared = Arg_string::find_arg(args, "irq_shared").bool_value(false);
if (shared) {
PWRN("IRQ sharing not supported");
/* FIXME error condition -> exception */
return;
}
long irq_number = Arg_string::find_arg(args, "irq_number").long_value(-1); long irq_number = Arg_string::find_arg(args, "irq_number").long_value(-1);
if (irq_number == -1 || !irq_alloc || if (irq_number == -1) {
irq_alloc->alloc_addr(1, irq_number).is_error()) { PERR("invalid IRQ number requested");
PERR("unavailable IRQ %lx requested", irq_number);
/* FIXME error condition -> exception */ throw Root::Unavailable();
return;
} }
_irq_number = irq_number;
/* initialize capability */ /* check if IRQ thread was started before */
_irq_cap = _ep.manage(this); _proxy = Irq_proxy_component::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc);
if (!_proxy) {
PERR("unavailable IRQ %lx requested", irq_number);
throw Root::Unavailable();
}
_irq_number = irq_number;
} }
Irq_session_component::~Irq_session_component() Irq_session_component::~Irq_session_component()
{ {
L4_Word_t res = L4_DeassociateInterrupt(irqno_to_threadid(_irq_number)); if (!_proxy) return;
if (res != 1) { if (_irq_sigh.valid())
PERR("L4_DeassociateInterrupt failed"); _proxy->remove_sharer(&_irq_sigh);
}
} }
Irq_signal Irq_session_component::signal() void Irq_session_component::sigh(Genode::Signal_context_capability sigh)
{ {
PDBG("not implemented;"); if (!_proxy) {
return Irq_signal(); PERR("signal handler got not registered - irq thread unavailable");
return;
}
Genode::Signal_context_capability old = _irq_sigh;
if (old.valid() && !sigh.valid())
_proxy->remove_sharer(&_irq_sigh);
_irq_sigh = sigh;
if (!old.valid() && sigh.valid())
_proxy->add_sharer(&_irq_sigh);
} }

View File

@ -26,11 +26,6 @@ namespace Genode { struct Irq_session_client; }
*/ */
struct Genode::Irq_session_client : Rpc_client<Irq_session> struct Genode::Irq_session_client : Rpc_client<Irq_session>
{ {
/*
* FIXME: This is used only client-internal and could thus be protected.
*/
Irq_signal const irq_signal;
/** /**
* Constructor * Constructor
* *
@ -38,8 +33,7 @@ struct Genode::Irq_session_client : Rpc_client<Irq_session>
*/ */
explicit Irq_session_client(Irq_session_capability const & session) explicit Irq_session_client(Irq_session_capability const & session)
: :
Rpc_client<Irq_session>(session), Rpc_client<Irq_session>(session)
irq_signal(signal())
{ } { }
@ -47,9 +41,9 @@ struct Genode::Irq_session_client : Rpc_client<Irq_session>
** Irq_session ** ** Irq_session **
*****************/ *****************/
Irq_signal signal() override { return call<Rpc_signal>(); } void ack_irq() override;
void wait_for_irq() override; void sigh(Signal_context_capability sigh) override { call<Rpc_sigh>(sigh); }
}; };
#endif /* _INCLUDE__IRQ_SESSION__CLIENT_H_ */ #endif /* _INCLUDE__IRQ_SESSION__CLIENT_H_ */

View File

@ -21,22 +21,47 @@ namespace Genode { struct Irq_connection; }
struct Genode::Irq_connection : Connection<Irq_session>, Irq_session_client struct Genode::Irq_connection : Connection<Irq_session>, Irq_session_client
{ {
/**
* Constructor private:
*
* \param irq physical interrupt number Genode::Signal_receiver _sig_rec;
* \param trigger interrupt trigger (e.g., level/edge) Genode::Signal_context _sigh_ctx;
* \param polarity interrupt trigger polarity (e.g., low/high) Genode::Signal_context_capability _sigh_cap;
*/
Irq_connection(unsigned irq, public:
Irq_session::Trigger trigger = Irq_session::TRIGGER_UNCHANGED,
Irq_session::Polarity polarity = Irq_session::POLARITY_UNCHANGED) /**
: * Constructor
Connection<Irq_session>( *
session("ram_quota=4K, irq_number=%u, irq_trigger=%u, irq_polarity=%u", * \param irq physical interrupt number
irq, trigger, polarity)), * \param trigger interrupt trigger (e.g., level/edge)
Irq_session_client(cap()) * \param polarity interrupt trigger polarity (e.g., low/high)
{ } */
Irq_connection(unsigned irq,
Irq_session::Trigger trigger = Irq_session::TRIGGER_UNCHANGED,
Irq_session::Polarity polarity = Irq_session::POLARITY_UNCHANGED)
:
Connection<Irq_session>(
session("ram_quota=4K, irq_number=%u, irq_trigger=%u, irq_polarity=%u",
irq, trigger, polarity)),
Irq_session_client(cap()),
_sigh_cap(_sig_rec.manage(&_sigh_ctx))
{
/* register default signal handler */
Irq_session_client::sigh(_sigh_cap);
}
~Irq_connection()
{
Irq_session_client::sigh(Genode::Signal_context_capability());
_sig_rec.dissolve(&_sigh_ctx);
}
/**
* Convenience function to acknowledge last IRQ and to block calling
* thread until next IRQ fires.
*/
void wait_for_irq();
}; };
#endif /* _INCLUDE__IRQ_SESSION__CONNECTION_H_ */ #endif /* _INCLUDE__IRQ_SESSION__CONNECTION_H_ */

View File

@ -6,8 +6,7 @@
* *
* An open IRQ session represents a valid IRQ attachment/association. * An open IRQ session represents a valid IRQ attachment/association.
* Initially, the interrupt is masked and will only occur if enabled. This is * Initially, the interrupt is masked and will only occur if enabled. This is
* done by calling wait_for_irq(). When the interrupt is delivered to the * done by calling ack_irq().
* client, it was acknowledged and masked at the interrupt controller before.
* *
* Disassociation from an IRQ is done by closing the session. * Disassociation from an IRQ is done by closing the session.
*/ */
@ -22,25 +21,15 @@
#ifndef _INCLUDE__IRQ_SESSION__IRQ_SESSION_H_ #ifndef _INCLUDE__IRQ_SESSION__IRQ_SESSION_H_
#define _INCLUDE__IRQ_SESSION__IRQ_SESSION_H_ #define _INCLUDE__IRQ_SESSION__IRQ_SESSION_H_
#include <base/signal.h>
#include <base/capability.h> #include <base/capability.h>
#include <session/session.h> #include <session/session.h>
namespace Genode { namespace Genode {
struct Irq_session; struct Irq_session;
struct Irq_signal;
} }
/**
* Information that enables a user to await and ack an IRQ directly
*/
struct Genode::Irq_signal
{
unsigned receiver_id;
unsigned context_id;
};
struct Genode::Irq_session : Session struct Genode::Irq_session : Session
{ {
/** /**
@ -59,17 +48,14 @@ struct Genode::Irq_session : Session
virtual ~Irq_session() { } virtual ~Irq_session() { }
/** /**
* Await the next occurence of the interrupt of this session * Acknowledge handling of last interrupt - re-enables interrupt reception
*/ */
virtual void wait_for_irq() = 0; virtual void ack_irq() = 0;
/** /**
* Get information for direct interrupt handling * Register irq signal handler
*
* FIXME: This is used only client-internal and could thus be protected.
*/ */
virtual Irq_signal signal() = 0; virtual void sigh(Genode::Signal_context_capability sigh) = 0;
/************* /*************
** Session ** ** Session **
@ -82,9 +68,9 @@ struct Genode::Irq_session : Session
** RPC declaration ** ** RPC declaration **
*********************/ *********************/
GENODE_RPC(Rpc_wait_for_irq, void, wait_for_irq); GENODE_RPC(Rpc_ack_irq, void, ack_irq);
GENODE_RPC(Rpc_signal, Irq_signal, signal); GENODE_RPC(Rpc_sigh, void, sigh, Genode::Signal_context_capability);
GENODE_RPC_INTERFACE(Rpc_wait_for_irq, Rpc_signal); GENODE_RPC_INTERFACE(Rpc_ack_irq, Rpc_sigh);
}; };
#endif /* _INCLUDE__IRQ_SESSION__IRQ_SESSION_H_ */ #endif /* _INCLUDE__IRQ_SESSION__IRQ_SESSION_H_ */

View File

@ -11,9 +11,18 @@
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
*/ */
#include <irq_session/client.h> #include <irq_session/connection.h>
void Genode::Irq_session_client::wait_for_irq() void Genode::Irq_session_client::ack_irq()
{ {
call<Rpc_wait_for_irq>(); call<Rpc_ack_irq>();
}
void Genode::Irq_connection::wait_for_irq()
{
ack_irq();
Signal s = _sig_rec.wait_for_signal();
if (s.num() != 1)
PWRN("unexpected number of IRqs received %u", s.num());
} }

View File

@ -9,36 +9,34 @@
#define _CORE__INCLUDE__IRQ_PROXY_H_ #define _CORE__INCLUDE__IRQ_PROXY_H_
#include <base/env.h> #include <base/env.h>
#include <util.h>
#include <base/thread.h>
namespace Genode { namespace Genode {
class Irq_blocker; class Irq_sigh;
template <typename THREAD> class Irq_proxy; template <typename THREAD> class Irq_proxy;
class Irq_thread_dummy;
class Irq_proxy_single;
} }
class Genode::Irq_blocker : public Genode::List<Genode::Irq_blocker>::Element class Genode::Irq_sigh : public Genode::Signal_context_capability,
public Genode::List<Genode::Irq_sigh>::Element
{ {
private:
Lock _wait_lock;
public: public:
Irq_blocker() : _wait_lock(Lock::LOCKED) { } inline Irq_sigh * operator= (const Signal_context_capability &cap)
{
Signal_context_capability::operator=(cap);
return this;
}
void block() { _wait_lock.lock(); } Irq_sigh() { }
void unblock() { _wait_lock.unlock(); }
void notify() { Genode::Signal_transmitter(*this).submit(1); }
}; };
/* /*
* Proxy thread that associates to the interrupt and unblocks waiting irqctrl * Proxy thread that associates to the interrupt and unblocks waiting irqctrl
* threads. Maybe, we should utilize our signals for interrupt delivery... * threads.
* *
* XXX resources are not accounted as the interrupt is shared * XXX resources are not accounted as the interrupt is shared
*/ */
@ -56,8 +54,8 @@ class Genode::Irq_proxy : public THREAD,
Lock _mutex; /* protects this object */ Lock _mutex; /* protects this object */
int _num_sharers; /* number of clients sharing this IRQ */ int _num_sharers; /* number of clients sharing this IRQ */
Semaphore _sleep; /* wake me up if aspired blockers return */ Semaphore _sleep; /* wake me up if aspired blockers return */
List<Irq_blocker> _blocker_list; List<Irq_sigh> _sigh_list;
int _num_blockers; /* number of currently blocked clients */ int _num_acknowledgers; /* number of currently blocked clients */
bool _woken_up; /* client decided to wake me up - bool _woken_up; /* client decided to wake me up -
this prevents multiple wakeups this prevents multiple wakeups
to happen during initialization */ to happen during initialization */
@ -102,20 +100,8 @@ class Genode::Irq_proxy : public THREAD,
while (1) { while (1) {
_wait_for_irq(); _wait_for_irq();
{ /* notify all */
Lock::Guard lock_guard(_mutex); notify_about_irq(1);
/* inform blocked clients */
Irq_blocker *b;
while ((b = _blocker_list.first())) {
_blocker_list.remove(b);
b->unblock();
}
/* reset blocker state */
_num_blockers = 0;
_woken_up = false;
}
/* /*
* We must wait for all clients to ack their interrupt, * We must wait for all clients to ack their interrupt,
@ -146,7 +132,8 @@ class Genode::Irq_proxy : public THREAD,
: :
THREAD(_construct_name(irq_number)), THREAD(_construct_name(irq_number)),
_startup_lock(Lock::LOCKED), _irq_number(irq_number), _startup_lock(Lock::LOCKED), _irq_number(irq_number),
_mutex(Lock::UNLOCKED), _num_sharers(0), _num_blockers(0), _woken_up(false) _mutex(Lock::UNLOCKED), _num_sharers(0), _num_acknowledgers(0), _woken_up(false)
{ } { }
/** /**
@ -163,43 +150,68 @@ class Genode::Irq_proxy : public THREAD,
} }
/** /**
* Block until interrupt occured * Acknowledgements of clients
*/ */
virtual void wait_for_irq() virtual bool ack_irq()
{ {
Irq_blocker blocker; Lock::Guard lock_guard(_mutex);
{
Lock::Guard lock_guard(_mutex);
_blocker_list.insert(&blocker); _num_acknowledgers++;
_num_blockers++;
/* /*
* The proxy thread is woken up if no client woke it up before * The proxy thread has to be woken up if no client woke it up
* and this client is the last aspired blocker. * before and this client is the last aspired acknowledger.
*/ */
if (!_woken_up && _num_blockers == _num_sharers) { if (!_woken_up && _num_acknowledgers == _num_sharers) {
_sleep.up(); _sleep.up();
_woken_up = true; _woken_up = true;
}
} }
blocker.block();
return _woken_up;
} }
/**
* Notify all clients about irq
*/
void notify_about_irq(unsigned)
{
Lock::Guard lock_guard(_mutex);
/* reset acknowledger state */
_num_acknowledgers = 0;
_woken_up = false;
/* inform blocked clients */
for (Irq_sigh * s = _sigh_list.first(); s ; s = s->next())
s->notify();
}
long irq_number() const { return _irq_number; } long irq_number() const { return _irq_number; }
virtual bool add_sharer() virtual bool add_sharer(Irq_sigh *s)
{ {
Lock::Guard lock_guard(_mutex); Lock::Guard lock_guard(_mutex);
++_num_sharers; ++_num_sharers;
_sigh_list.insert(s);
return true; return true;
} }
virtual void remove_sharer() virtual void remove_sharer(Irq_sigh *s)
{ {
Lock::Guard lock_guard(_mutex); Lock::Guard lock_guard(_mutex);
_sigh_list.remove(s);
--_num_sharers; --_num_sharers;
if (_woken_up)
return;
if (_num_acknowledgers == _num_sharers) {
_sleep.up();
_woken_up = true;
}
} }
template <typename PROXY> template <typename PROXY>
@ -225,51 +237,4 @@ class Genode::Irq_proxy : public THREAD,
} }
}; };
/**
* Dummy thread
*/
class Genode::Irq_thread_dummy
{
public:
Irq_thread_dummy(char const *name) { }
void start() { }
};
/**
* Non-threaded proxy that disables shared interrupts
*/
class Genode::Irq_proxy_single : public Genode::Irq_proxy<Genode::Irq_thread_dummy>
{
protected:
void _start()
{
_associate();
}
public:
Irq_proxy_single(long irq_number) : Irq_proxy(irq_number) { }
bool add_sharer()
{
Lock::Guard lock_guard(_mutex);
if (_num_sharers)
return false;
_num_sharers = 1;
return true;
}
void wait_for_irq()
{
_wait_for_irq();
_ack_irq();
}
};
#endif /* _CORE__INCLUDE__IRQ_PROXY_H_ */ #endif /* _CORE__INCLUDE__IRQ_PROXY_H_ */

View File

@ -1,13 +1,12 @@
/* /*
* \brief IRQ root interface * \brief IRQ root interface
* \author Christian Helmuth * \author Christian Helmuth
* \author Alexander Boettcher
* \date 2007-09-13 * \date 2007-09-13
*
* FIXME locking
*/ */
/* /*
* Copyright (C) 2007-2013 Genode Labs GmbH * Copyright (C) 2007-2015 Genode Labs GmbH
* *
* This file is part of the Genode OS framework, which is distributed * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
@ -16,98 +15,37 @@
#ifndef _CORE__INCLUDE__IRQ_ROOT_H_ #ifndef _CORE__INCLUDE__IRQ_ROOT_H_
#define _CORE__INCLUDE__IRQ_ROOT_H_ #define _CORE__INCLUDE__IRQ_ROOT_H_
/* Genode includes */ #include <root/component.h>
#include <util/arg_string.h>
#include <base/allocator.h>
#include <root/root.h>
#include <base/rpc_server.h>
/* core includes */
#include <irq_session_component.h> #include <irq_session_component.h>
namespace Genode { namespace Genode { class Irq_root; }
class Irq_root : public Rpc_object<Typed_root<Irq_session> > class Genode::Irq_root : public Root_component<Irq_session_component>
{ {
private: private:
Cap_session *_cap_session; Range_allocator *_irq_alloc; /* platform irq allocator */
Range_allocator *_irq_alloc; /* platform irq allocator */
Allocator *_md_alloc; /* meta-data allocator */
List<Irq_session_component> _sessions; /* started irq sessions */
public: protected:
/** Irq_session_component *_create_session(const char *args) {
* Constructor return new (md_alloc()) Irq_session_component(_irq_alloc, args); }
*
* \param cap_session capability allocator
* \param irq_alloc IRQ range that can be assigned to clients
* \param md_alloc meta-data allocator to be used by root component
*/
Irq_root(Cap_session *cap_session,
Range_allocator *irq_alloc,
Allocator *md_alloc)
: _cap_session(cap_session), _irq_alloc(irq_alloc), _md_alloc(md_alloc) { }
public:
/******************** /**
** Root interface ** * Constructor
********************/ *
* \param session_ep entry point for managing irq session objects
Session_capability session(Session_args const &args, Affinity const &affinity) * \param irq_alloc IRQ range that can be assigned to clients
{ * \param md_alloc meta-data allocator to be used by root component
if (!args.is_valid_string()) throw Invalid_args(); */
Irq_root(Rpc_entrypoint *session_ep, Range_allocator *irq_alloc,
/* Allocator *md_alloc)
* We need to decrease 'ram_quota' by :
* the size of the session object. Root_component<Irq_session_component>(session_ep, md_alloc),
*/ _irq_alloc(irq_alloc) { }
size_t ram_quota = Arg_string::find_arg(args.string(), "ram_quota").ulong_value(0); };
long remaining_ram_quota = ram_quota - sizeof(Irq_session_component) -
_md_alloc->overhead(sizeof(Irq_session_component));
if (remaining_ram_quota < 0) {
PERR("Insufficient ram quota, provided=%zu, required=%zu",
ram_quota, sizeof(Irq_session_component) +
_md_alloc->overhead(sizeof(Irq_session_component)));
return Session_capability();
}
Irq_session_component *s;
try {
s = new (_md_alloc) Irq_session_component(_cap_session, _irq_alloc, args.string());
} catch (Allocator::Out_of_memory) { return Session_capability(); }
if (!s->cap().valid())
return Session_capability();
_sessions.insert(s);
return s->cap();
}
void upgrade(Session_capability, Upgrade_args const &)
{
/* there is no need to upgrade an IRQ session */
}
void close(Session_capability session)
{
Irq_session_component *s = _sessions.first();
for (; s; s = s->next()) {
if (s->cap().local_name() == session.local_name())
break;
}
if (!s) return;
_sessions.remove(s);
/* XXX Currently we support only one client... */
destroy(_md_alloc, s);
}
};
}
#endif /* _CORE__INCLUDE__IRQ_ROOT_H_ */ #endif /* _CORE__INCLUDE__IRQ_ROOT_H_ */

View File

@ -14,128 +14,51 @@
#ifndef _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_ #ifndef _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_
#define _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_ #define _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_
#include <base/lock.h>
#include <base/rpc_server.h> #include <base/rpc_server.h>
#include <base/rpc_client.h> #include <base/rpc_client.h>
#include <util/list.h> #include <util/list.h>
#include <irq_session/irq_session.h> #include <irq_session/irq_session.h>
#include <irq_session/capability.h> #include <irq_session/capability.h>
#include <irq_proxy.h>
/* XXX Notes
*
* - each H/W IRQ is an irq thread
* - each irq thread has an Rpc_entrypoint
* -> irq thread is special Server_activation
* -> IRQ session is Rpc_object
*
* - session("IRQ", "irq_num=<num>") -> Native_capability(irq_thread, cap)
* - cap must be generated at CAP
* - cap must be managed by irq_thread-local Rpc_entrypoint
*
* - irq thread states
* 1. wait_for_client --[ client calls wait_for_irq ]--> 2.
* 2. wait_for_irq --[ kernel signals irq ]--> 3.
* 3. irq_occured --[ inform client about occurence ]--> 1.
*
* - irq thread roles
* - Irq_server (Ipc_server) for client
* - Fiasco_irq_client (Ipc_client) at kernel
*/
namespace Genode { namespace Genode {
class Irq_proxy_component;
class Irq_session_component : public Rpc_object<Irq_session>, class Irq_session_component;
public List<Irq_session_component>::Element
{
private:
struct Irq_control
{
GENODE_RPC(Rpc_associate_to_irq, bool, associate_to_irq, unsigned);
GENODE_RPC_INTERFACE(Rpc_associate_to_irq);
};
struct Irq_control_client : Rpc_client<Irq_control>
{
Irq_control_client(Capability<Irq_control> cap)
: Rpc_client<Irq_control>(cap) { }
bool associate_to_irq(unsigned irq_number) {
return call<Rpc_associate_to_irq>(irq_number); }
};
struct Irq_control_component : Rpc_object<Irq_control,
Irq_control_component>
{
/**
* Associate to IRQ at Fiasco
*
* This is executed by the IRQ server activation itself.
*/
bool associate_to_irq(unsigned irq_number);
};
unsigned _irq_number;
Range_allocator *_irq_alloc;
enum { STACK_SIZE = 2048 };
Rpc_entrypoint _ep;
/*
* On Pistachio, an IRQ is unmasked right after attaching.
* Hence, the kernel may send an IRQ IPC when the IRQ hander is
* not explicitly waiting for an IRQ but when it is waiting for
* a client's 'wait_for_irq' RPC call. To avoid this conflict, we
* lazily associate to the IRQ when calling the 'wait_for_irq'
* function for the first time. We use the '_irq_attached' flag
* for detecting the first call. On other kernels, this variable
* may be unused.
*/
unsigned _irq_attached; /* true if IRQ is already attached */
/********************************************
** IRQ control server (internal use only) **
********************************************/
Irq_control_component _control_component; /* ctrl component */
Capability<Irq_control> _control_cap; /* capability for ctrl server */
Irq_control_client _control_client; /* ctrl client */
Capability<Irq_session> _irq_cap; /* capability for IRQ */
public:
/**
* Constructor
*
* \param cap_session capability session to use
* \param irq_alloc platform-dependent IRQ allocator
* \param args session construction arguments
*/
Irq_session_component(Cap_session *cap_session,
Range_allocator *irq_alloc,
const char *args);
/**
* Destructor
*/
~Irq_session_component();
/**
* Return capability to this session
*
* If an initialization error occurs, returned _cap is invalid.
*/
Capability<Irq_session> cap() const { return _irq_cap; }
/***************************
** Irq session interface **
***************************/
void wait_for_irq();
Irq_signal signal();
};
} }
class Genode::Irq_session_component : public Rpc_object<Irq_session>,
public List<Irq_session_component>::Element
{
private:
unsigned _irq_number;
Range_allocator *_irq_alloc;
Irq_proxy_component *_proxy;
Irq_sigh _irq_sigh;
public:
/**
* Constructor
*
* \param irq_alloc platform-dependent IRQ allocator
* \param args session construction arguments
*/
Irq_session_component(Range_allocator *irq_alloc,
const char *args);
/**
* Destructor
*/
~Irq_session_component();
/***************************
** Irq session interface **
***************************/
void ack_irq();
void sigh(Signal_context_capability) override;
};
#endif /* _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_ */ #endif /* _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_ */

View File

@ -220,8 +220,7 @@ int main()
static Log_root log_root (e, &sliced_heap); static Log_root log_root (e, &sliced_heap);
static Io_mem_root io_mem_root (e, e, platform()->io_mem_alloc(), static Io_mem_root io_mem_root (e, e, platform()->io_mem_alloc(),
platform()->ram_alloc(), &sliced_heap); platform()->ram_alloc(), &sliced_heap);
static Irq_root irq_root (core_env()->cap_session(), static Irq_root irq_root (e, platform()->irq_alloc(), &sliced_heap);
platform()->irq_alloc(), &sliced_heap);
static Trace::Root trace_root (e, &sliced_heap, trace_sources, trace_policies); static Trace::Root trace_root (e, &sliced_heap, trace_sources, trace_policies);
/* /*