mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-19 11:16:57 +00:00
Core: Shared IRQ support for Nova/FOC/OKL4
Implement shared IRQs using 'Irq_proxy' class. Nova: Added global worker 'Irq_thread' support in core and adapted Irq_session. FOC: Adapted IRQ session code, x86 has shared IRQ support, ARM uses the old model. Read and set 'mode' argument (from MADT) in 'Irq_session'. OKL4: Use generic 'Irq_proxy' Fixes issue #390
This commit is contained in:
parent
5549f6413b
commit
4a3d852b65
@ -15,4 +15,4 @@
|
|||||||
|
|
||||||
void Genode::Platform::_setup_io_port_alloc() { }
|
void Genode::Platform::_setup_io_port_alloc() { }
|
||||||
|
|
||||||
void Genode::Platform::setup_irq_mode(unsigned irq_number) { }
|
void Genode::Platform::setup_irq_mode(unsigned, unsigned, unsigned) { }
|
||||||
|
29
base-foc/src/core/include/arm/irq_proxy_component.h
Normal file
29
base-foc/src/core/include/arm/irq_proxy_component.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* \brief Base class for shared interrupts on ARM
|
||||||
|
* \author Sebastian Sumpf
|
||||||
|
* \date 2012-10-05
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 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_ */
|
||||||
|
|
@ -23,48 +23,13 @@
|
|||||||
|
|
||||||
namespace Genode {
|
namespace Genode {
|
||||||
|
|
||||||
|
class Irq_proxy_component;
|
||||||
|
|
||||||
class Irq_session_component : public Rpc_object<Irq_session>,
|
class Irq_session_component : public Rpc_object<Irq_session>,
|
||||||
public List<Irq_session_component>::Element
|
public List<Irq_session_component>::Element
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
class Interrupt : public Avl_node<Interrupt>
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
Cap_index* _cap;
|
|
||||||
Semaphore _sem;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
unsigned number;
|
|
||||||
|
|
||||||
Interrupt();
|
|
||||||
|
|
||||||
bool higher(Interrupt *n);
|
|
||||||
Interrupt* find_by_num(unsigned num);
|
|
||||||
|
|
||||||
Native_thread capability() { return _cap->kcap(); }
|
|
||||||
Semaphore* semaphore() { return &_sem; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Interrupt_handler : public Thread<4096>
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
Interrupt_handler() { start(); }
|
|
||||||
|
|
||||||
void entry();
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
static Native_thread handler_cap();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
Interrupt _irq;
|
|
||||||
Range_allocator *_irq_alloc;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Each IRQ session uses a dedicated server activation
|
* Each IRQ session uses a dedicated server activation
|
||||||
@ -73,8 +38,7 @@ namespace Genode {
|
|||||||
Rpc_entrypoint _ep;
|
Rpc_entrypoint _ep;
|
||||||
|
|
||||||
Irq_session_capability _irq_cap;
|
Irq_session_capability _irq_cap;
|
||||||
|
Irq_proxy_component *_proxy;
|
||||||
static Avl_tree<Interrupt>* _irqs();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -129,9 +129,10 @@ namespace Genode {
|
|||||||
Core_pager *core_pager();
|
Core_pager *core_pager();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set interrupt mode (e.g., level or edge)
|
* Set interrupt trigger/polarity (e.g., level or edge, high or low)
|
||||||
*/
|
*/
|
||||||
static void setup_irq_mode(unsigned irq_number);
|
static void setup_irq_mode(unsigned irq_number, unsigned trigger,
|
||||||
|
unsigned polarity);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
24
base-foc/src/core/include/x86/irq_proxy_component.h
Normal file
24
base-foc/src/core/include/x86/irq_proxy_component.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* \brief Base class for shared interrupts on x86
|
||||||
|
* \author Sebastian Sumpf
|
||||||
|
* \date 2012-10-05
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 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_ */
|
||||||
|
|
@ -2,6 +2,7 @@
|
|||||||
* \brief Fiasco.OC-specific core implementation of IRQ sessions
|
* \brief Fiasco.OC-specific core implementation of IRQ sessions
|
||||||
* \author Christian Helmuth
|
* \author Christian Helmuth
|
||||||
* \author Stefan Kalkowski
|
* \author Stefan Kalkowski
|
||||||
|
* \author Sebastian Sumpf
|
||||||
* \date 2007-09-13
|
* \date 2007-09-13
|
||||||
*
|
*
|
||||||
* FIXME ram quota missing
|
* FIXME ram quota missing
|
||||||
@ -20,6 +21,7 @@
|
|||||||
|
|
||||||
/* 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>
|
||||||
@ -34,36 +36,197 @@ namespace Fiasco {
|
|||||||
|
|
||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
|
||||||
|
namespace Genode {
|
||||||
Irq_session_component::Interrupt*
|
class Interrupt_handler;
|
||||||
Irq_session_component::Interrupt::find_by_num(unsigned num)
|
class Irq_proxy_component;
|
||||||
{
|
|
||||||
if (number == num) return this;
|
|
||||||
|
|
||||||
Interrupt *n = Avl_node<Interrupt>::child(num > number);
|
|
||||||
return n ? n->find_by_num(num) : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
bool Irq_session_component::Interrupt::higher(Irq_session_component::Interrupt *n)
|
* Dispatches interrupts from kernel
|
||||||
|
*/
|
||||||
|
class Genode::Interrupt_handler : public Thread<4096>
|
||||||
{
|
{
|
||||||
return n->number > number;
|
private:
|
||||||
}
|
|
||||||
|
|
||||||
|
Interrupt_handler() { start(); }
|
||||||
|
|
||||||
Irq_session_component::Interrupt::Interrupt()
|
public:
|
||||||
: _cap(cap_map()->insert(platform_specific()->cap_id_alloc()->alloc())),
|
|
||||||
_sem(), number(0) {}
|
|
||||||
|
|
||||||
|
void entry();
|
||||||
|
|
||||||
Native_thread Irq_session_component::Interrupt_handler::handler_cap()
|
static Native_thread handler_cap()
|
||||||
{
|
{
|
||||||
static Interrupt_handler handler;
|
static Interrupt_handler handler;
|
||||||
return handler._thread_cap.dst();
|
return handler._thread_cap.dst();
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
void Irq_session_component::Interrupt_handler::entry()
|
/**
|
||||||
|
* Irq_proxy interface implementation
|
||||||
|
*/
|
||||||
|
class Genode::Irq_proxy_component : public Irq_proxy_base
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
Cap_index *_cap;
|
||||||
|
Semaphore _sem;
|
||||||
|
long _trigger; /* interrupt trigger */
|
||||||
|
long _polarity; /* interrupt polarity */
|
||||||
|
|
||||||
|
Native_thread _capability() const { return _cap->kcap(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
bool _associate()
|
||||||
|
{
|
||||||
|
using namespace Fiasco;
|
||||||
|
if (l4_error(l4_factory_create_irq(L4_BASE_FACTORY_CAP, _capability()))) {
|
||||||
|
PERR("l4_factory_create_irq failed!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (l4_error(l4_icu_bind(L4_BASE_ICU_CAP, _irq_number, _capability()))) {
|
||||||
|
PERR("Binding IRQ%ld to the ICU failed", _irq_number);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set interrupt mode */
|
||||||
|
Platform::setup_irq_mode(_irq_number, _trigger, _polarity);
|
||||||
|
|
||||||
|
if (l4_error(l4_irq_attach(_capability(), _irq_number,
|
||||||
|
Interrupt_handler::handler_cap()))) {
|
||||||
|
PERR("Error attaching to IRQ %ld", _irq_number);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _wait_for_irq()
|
||||||
|
{
|
||||||
|
using namespace Fiasco;
|
||||||
|
|
||||||
|
int err;
|
||||||
|
l4_msgtag_t tag = l4_irq_unmask(_capability());
|
||||||
|
if ((err = l4_ipc_error(tag, l4_utcb())))
|
||||||
|
PERR("IRQ unmask: %d\n", err);
|
||||||
|
|
||||||
|
_sem.down();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _ack_irq() { }
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Irq_proxy_component(long irq_number)
|
||||||
|
:
|
||||||
|
Irq_proxy_base(irq_number),
|
||||||
|
_cap(cap_map()->insert(platform_specific()->cap_id_alloc()->alloc())),
|
||||||
|
_sem(), _trigger(-1), _polarity(-1) { }
|
||||||
|
|
||||||
|
Semaphore *semaphore() { return &_sem; }
|
||||||
|
|
||||||
|
void start(long trigger, long polarity)
|
||||||
|
{
|
||||||
|
_trigger = trigger;
|
||||||
|
_polarity = polarity;
|
||||||
|
_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool match_mode(long trigger, long polarity)
|
||||||
|
{
|
||||||
|
if (trigger == Irq_session::TRIGGER_UNCHANGED &&
|
||||||
|
polarity == Irq_session::POLARITY_UNCHANGED)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (_trigger < 0 && _polarity < 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return _trigger == trigger && _polarity == polarity;
|
||||||
|
}
|
||||||
|
|
||||||
|
long trigger() const { return _trigger; }
|
||||||
|
long polarity() const { return _polarity; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/********************************
|
||||||
|
** IRQ session implementation **
|
||||||
|
********************************/
|
||||||
|
|
||||||
|
|
||||||
|
Irq_session_component::Irq_session_component(Cap_session *cap_session,
|
||||||
|
Range_allocator *irq_alloc,
|
||||||
|
const char *args)
|
||||||
|
:
|
||||||
|
_ep(cap_session, STACK_SIZE, "irqctrl"),
|
||||||
|
_proxy(0)
|
||||||
|
{
|
||||||
|
using namespace Fiasco;
|
||||||
|
|
||||||
|
long irq_number = Arg_string::find_arg(args, "irq_number").long_value(-1);
|
||||||
|
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);
|
||||||
|
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;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* temorary hack for fiasco.oc using the local-apic,
|
||||||
|
* where old pic-line 0 maps to 2
|
||||||
|
*/
|
||||||
|
if (irq_number == 0)
|
||||||
|
irq_number = 2;
|
||||||
|
|
||||||
|
if (!(_proxy = Irq_proxy_component::get_irq_proxy<Irq_proxy_component>(irq_number,
|
||||||
|
irq_alloc))) {
|
||||||
|
PERR("No proxy for IRQ %lu found", irq_number);
|
||||||
|
throw Root::Unavailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sanity check */
|
||||||
|
if (!_proxy->match_mode(irq_trigger, irq_polarity)) {
|
||||||
|
PERR("Interrupt mode mismatch: IRQ %ld current mode: t: %ld p: %ld"
|
||||||
|
"request mode: trg: %ld p: %ld",
|
||||||
|
irq_number, _proxy->trigger(), _proxy->polarity(),
|
||||||
|
irq_trigger, irq_polarity);
|
||||||
|
throw Root::Unavailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set interrupt mode and start proxy */
|
||||||
|
_proxy->start(irq_trigger, irq_polarity);
|
||||||
|
|
||||||
|
if (!_proxy->add_sharer())
|
||||||
|
throw Root::Unavailable();
|
||||||
|
|
||||||
|
/* initialize capability */
|
||||||
|
_irq_cap = _ep.manage(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Irq_session_component::wait_for_irq()
|
||||||
|
{
|
||||||
|
_proxy->wait_for_irq();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Irq_session_component::~Irq_session_component()
|
||||||
|
{
|
||||||
|
PERR("Implement me, immediately!");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************
|
||||||
|
** Interrupt handler implemtentation **
|
||||||
|
***************************************/
|
||||||
|
|
||||||
|
void Interrupt_handler::entry()
|
||||||
{
|
{
|
||||||
using namespace Fiasco;
|
using namespace Fiasco;
|
||||||
|
|
||||||
@ -76,81 +239,11 @@ void Irq_session_component::Interrupt_handler::entry()
|
|||||||
if ((err = l4_ipc_error(tag, l4_utcb())))
|
if ((err = l4_ipc_error(tag, l4_utcb())))
|
||||||
PERR("IRQ receive: %d\n", err);
|
PERR("IRQ receive: %d\n", err);
|
||||||
else {
|
else {
|
||||||
Interrupt *intr = _irqs()->first();
|
Irq_proxy_component *proxy;
|
||||||
if (intr) {
|
proxy = Irq_proxy_component::get_irq_proxy<Irq_proxy_component>(label);
|
||||||
intr = intr->find_by_num(label);
|
|
||||||
if (intr)
|
if (proxy)
|
||||||
intr->semaphore()->up();
|
proxy->semaphore()->up();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Avl_tree<Irq_session_component::Interrupt>* Irq_session_component::_irqs()
|
|
||||||
{
|
|
||||||
static Avl_tree<Interrupt> irqs;
|
|
||||||
return &irqs;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Irq_session_component::Irq_session_component(Cap_session *cap_session,
|
|
||||||
Range_allocator *irq_alloc,
|
|
||||||
const char *args)
|
|
||||||
:
|
|
||||||
_irq_alloc(irq_alloc),
|
|
||||||
_ep(cap_session, STACK_SIZE, "irqctrl")
|
|
||||||
{
|
|
||||||
using namespace Fiasco;
|
|
||||||
|
|
||||||
long irq_number = Arg_string::find_arg(args, "irq_number").long_value(-1);
|
|
||||||
if ((irq_number == -1) || _irq_alloc->alloc_addr(1, irq_number)) {
|
|
||||||
PERR("Unavailable IRQ %lx requested", irq_number);
|
|
||||||
throw Root::Invalid_args();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* temorary hack for fiasco.oc using the local-apic,
|
|
||||||
* where old pic-line 0 maps to 2
|
|
||||||
*/
|
|
||||||
if (irq_number == 0)
|
|
||||||
irq_number = 2;
|
|
||||||
|
|
||||||
_irq.number = irq_number;
|
|
||||||
Irq_session_component::_irqs()->insert(&_irq);
|
|
||||||
|
|
||||||
if (l4_error(l4_factory_create_irq(L4_BASE_FACTORY_CAP, _irq.capability())))
|
|
||||||
PERR("l4_factory_create_irq failed!");
|
|
||||||
|
|
||||||
if (l4_error(l4_icu_bind(L4_BASE_ICU_CAP, irq_number, _irq.capability())))
|
|
||||||
PERR("Binding IRQ%ld to the ICU failed", irq_number);
|
|
||||||
|
|
||||||
/* set interrupt mode */
|
|
||||||
Platform::setup_irq_mode(irq_number);
|
|
||||||
|
|
||||||
if (l4_error(l4_irq_attach(_irq.capability(), irq_number,
|
|
||||||
Interrupt_handler::handler_cap())))
|
|
||||||
PERR("Error attaching to IRQ %ld", irq_number);
|
|
||||||
|
|
||||||
/* initialize capability */
|
|
||||||
_irq_cap = _ep.manage(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Irq_session_component::wait_for_irq()
|
|
||||||
{
|
|
||||||
using namespace Fiasco;
|
|
||||||
|
|
||||||
int err;
|
|
||||||
l4_msgtag_t tag = l4_irq_unmask(_irq.capability());
|
|
||||||
if ((err = l4_ipc_error(tag, l4_utcb())))
|
|
||||||
PERR("IRQ unmask: %d\n", err);
|
|
||||||
|
|
||||||
_irq.semaphore()->down();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Irq_session_component::~Irq_session_component()
|
|
||||||
{
|
|
||||||
PERR("Implement me, immediately!");
|
|
||||||
}
|
|
||||||
|
@ -4,6 +4,8 @@ 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 io_port_session_component.cc $(GEN_CORE_DIR)/arm
|
vpath io_port_session_component.cc $(GEN_CORE_DIR)/arm
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ 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
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ 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
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
#include <base/printf.h>
|
#include <base/printf.h>
|
||||||
|
#include <irq_session/irq_session.h>
|
||||||
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@ -45,12 +46,28 @@ void Genode::Platform::_setup_io_port_alloc()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Genode::Platform::setup_irq_mode(unsigned irq_number)
|
void Genode::Platform::setup_irq_mode(unsigned irq_number, unsigned trigger,
|
||||||
|
unsigned polarity)
|
||||||
{
|
{
|
||||||
using namespace Fiasco;
|
using namespace Fiasco;
|
||||||
|
|
||||||
/* set IRQ below 16 to edge/high and others to level/low */
|
/*
|
||||||
l4_umword_t mode = irq_number < 16 ? L4_IRQ_F_POS_EDGE : L4_IRQ_F_LEVEL_LOW;
|
* Translate ACPI interrupt mode (trigger/polarity) to Fiasco APIC
|
||||||
|
* values. Default is edge/high for IRQs < 16 and level low for IRQs > 16
|
||||||
|
*/
|
||||||
|
l4_umword_t mode;
|
||||||
|
mode = (trigger == Irq_session::TRIGGER_LEVEL) ||
|
||||||
|
(irq_number > 15 && trigger == Irq_session::TRIGGER_UNCHANGED)
|
||||||
|
? L4_IRQ_F_LEVEL : L4_IRQ_F_EDGE;
|
||||||
|
|
||||||
|
mode |= (polarity == Irq_session::POLARITY_LOW) ||
|
||||||
|
(irq_number > 15 && polarity == Irq_session::POLARITY_UNCHANGED)
|
||||||
|
? L4_IRQ_F_NEG : L4_IRQ_F_POS;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set mode
|
||||||
|
*/
|
||||||
if (l4_error(l4_icu_set_mode(L4_BASE_ICU_CAP, irq_number, mode)))
|
if (l4_error(l4_icu_set_mode(L4_BASE_ICU_CAP, irq_number, mode)))
|
||||||
PERR("Setting mode for IRQ%u failed", irq_number);
|
PERR("Setting mode for IRQ%u failed", irq_number);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ include $(PRG_DIR)/../target.inc
|
|||||||
|
|
||||||
REQUIRES += x86
|
REQUIRES += x86
|
||||||
SRC_CC += x86/platform_x86.cc
|
SRC_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
|
||||||
|
|
||||||
|
@ -214,6 +214,9 @@ Pager_object::Pager_object(unsigned long badge)
|
|||||||
_state.singlestep = false;
|
_state.singlestep = false;
|
||||||
_state.sel_client_ec = Native_thread::INVALID_INDEX;
|
_state.sel_client_ec = Native_thread::INVALID_INDEX;
|
||||||
|
|
||||||
|
/* creates local EC */
|
||||||
|
Thread_base::start();
|
||||||
|
|
||||||
/* Create portal for exception handlers 0x0 - 0xd */
|
/* Create portal for exception handlers 0x0 - 0xd */
|
||||||
for (unsigned i = 0; i < PT_SEL_PAGE_FAULT; i++) {
|
for (unsigned i = 0; i < PT_SEL_PAGE_FAULT; i++) {
|
||||||
res = create_pt(exc_pt_sel() + i, pd_sel, _tid.ec_sel,
|
res = create_pt(exc_pt_sel() + i, pd_sel, _tid.ec_sel,
|
||||||
|
@ -243,6 +243,11 @@ Rpc_entrypoint::Rpc_entrypoint(Cap_session *cap_session, size_t stack_size,
|
|||||||
throw Cpu_session::Thread_creation_failed();
|
throw Cpu_session::Thread_creation_failed();
|
||||||
_tid.ec_sel = ec_cap.local_name();
|
_tid.ec_sel = ec_cap.local_name();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
/**
|
||||||
|
* Required for core threads (creates local EC)
|
||||||
|
*/
|
||||||
|
Thread_base::start();
|
||||||
|
|
||||||
_rcv_buf.rcv_prepare_pt_sel_window((Nova::Utcb *)&_context->utcb);
|
_rcv_buf.rcv_prepare_pt_sel_window((Nova::Utcb *)&_context->utcb);
|
||||||
|
|
||||||
|
@ -22,20 +22,20 @@
|
|||||||
|
|
||||||
namespace Genode {
|
namespace Genode {
|
||||||
|
|
||||||
|
class Irq_proxy_component;
|
||||||
|
|
||||||
class Irq_session_component : public Rpc_object<Irq_session>,
|
class Irq_session_component : public Rpc_object<Irq_session>,
|
||||||
public List<Irq_session_component>::Element
|
public List<Irq_session_component>::Element
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
unsigned _irq_number;
|
|
||||||
Range_allocator *_irq_alloc;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Each IRQ session uses a dedicated server activation
|
* Each IRQ session uses a dedicated server activation
|
||||||
*/
|
*/
|
||||||
enum { STACK_SIZE = 2048 };
|
enum { STACK_SIZE = 2048 };
|
||||||
Rpc_entrypoint _ep;
|
Rpc_entrypoint _ep;
|
||||||
Irq_session_capability _irq_cap;
|
Irq_session_capability _irq_cap;
|
||||||
|
Irq_proxy_component *_proxy;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -14,10 +14,13 @@
|
|||||||
|
|
||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
#include <base/printf.h>
|
#include <base/printf.h>
|
||||||
|
#include <base/sleep.h>
|
||||||
|
|
||||||
/* core includes */
|
/* core includes */
|
||||||
#include <irq_root.h>
|
#include <irq_root.h>
|
||||||
|
#include <irq_proxy.h>
|
||||||
#include <platform.h>
|
#include <platform.h>
|
||||||
|
#include <platform_pd.h>
|
||||||
|
|
||||||
/* NOVA includes */
|
/* NOVA includes */
|
||||||
#include <nova/syscalls.h>
|
#include <nova/syscalls.h>
|
||||||
@ -26,11 +29,129 @@
|
|||||||
|
|
||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
|
||||||
|
namespace Genode {
|
||||||
|
class Irq_proxy_component;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Global worker (i.e. thread with SC)
|
||||||
|
*/
|
||||||
|
class Irq_thread : public Thread_base
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
static void _thread_start()
|
||||||
|
{
|
||||||
|
Thread_base::myself()->entry();
|
||||||
|
sleep_forever();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Irq_thread(char const *name) : Thread_base(name, 1024 * sizeof(addr_t)) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create global EC, associate it to SC
|
||||||
|
*/
|
||||||
|
void start()
|
||||||
|
{
|
||||||
|
using namespace Nova;
|
||||||
|
addr_t pd_sel = Platform_pd::pd_core_sel();
|
||||||
|
addr_t utcb = reinterpret_cast<addr_t>(&_context->utcb);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Put IP on stack, it will be read from core pager in platform.cc
|
||||||
|
*/
|
||||||
|
addr_t *sp = reinterpret_cast<addr_t *>(_context->stack - sizeof(addr_t));
|
||||||
|
*sp = reinterpret_cast<addr_t>(_thread_start);
|
||||||
|
|
||||||
|
/* create global EC */
|
||||||
|
enum { CPU_NO = 0, GLOBAL = true };
|
||||||
|
uint8_t res = create_ec(_tid.ec_sel, pd_sel, CPU_NO,
|
||||||
|
utcb, (mword_t)sp, _tid.exc_pt_sel, GLOBAL);
|
||||||
|
if (res != NOVA_OK) {
|
||||||
|
PERR("%p - create_ec returned %d", this, res);
|
||||||
|
throw Cpu_session::Thread_creation_failed();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* map startup portal from main thread */
|
||||||
|
map_local((Utcb *)Thread_base::myself()->utcb(),
|
||||||
|
Obj_crd(PT_SEL_STARTUP, 0),
|
||||||
|
Obj_crd(_tid.exc_pt_sel + PT_SEL_STARTUP, 0));
|
||||||
|
|
||||||
|
/* create SC */
|
||||||
|
unsigned sc_sel = cap_selector_allocator()->alloc();
|
||||||
|
res = create_sc(sc_sel, pd_sel, _tid.ec_sel, Qpd());
|
||||||
|
if (res != NOVA_OK) {
|
||||||
|
PERR("%p - create_sc returned returned %d", this, res);
|
||||||
|
throw Cpu_session::Thread_creation_failed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Irq_proxy interface implementation
|
||||||
|
*/
|
||||||
|
class Genode::Irq_proxy_component : public Irq_proxy<Irq_thread>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
long _irq_sel; /* IRQ cap selector */
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
bool _associate()
|
||||||
|
{
|
||||||
|
/* alloc slector where IRQ will be mapped */
|
||||||
|
_irq_sel = cap_selector_allocator()->alloc();
|
||||||
|
|
||||||
|
/* since we run in APIC mode translate IRQ 0 (PIT) to 2 */
|
||||||
|
if (!_irq_number)
|
||||||
|
_irq_number = 2;
|
||||||
|
|
||||||
|
/* map IRQ number to selector */
|
||||||
|
int ret = map_local((Nova::Utcb *)Thread_base::myself()->utcb(),
|
||||||
|
Nova::Obj_crd(platform_specific()->gsi_base_sel() + _irq_number, 0),
|
||||||
|
Nova::Obj_crd(_irq_sel, 0),
|
||||||
|
true);
|
||||||
|
if (ret) {
|
||||||
|
PERR("Could not map IRQ %ld", _irq_number);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* assign IRQ to CPU */
|
||||||
|
enum { CPU = 0 };
|
||||||
|
Nova::assign_gsi(_irq_sel, 0, CPU);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _wait_for_irq()
|
||||||
|
{
|
||||||
|
if (Nova::sm_ctrl(_irq_sel, Nova::SEMAPHORE_DOWN))
|
||||||
|
nova_die();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _ack_irq() { }
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Irq_proxy_component(long irq_number) : Irq_proxy(irq_number)
|
||||||
|
{
|
||||||
|
_start();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef Irq_proxy<Irq_thread> Proxy;
|
||||||
|
|
||||||
|
|
||||||
void Irq_session_component::wait_for_irq()
|
void Irq_session_component::wait_for_irq()
|
||||||
{
|
{
|
||||||
if (Nova::sm_ctrl(_irq_number, Nova::SEMAPHORE_DOWN))
|
_proxy->wait_for_irq();
|
||||||
nova_die();
|
/* interrupt ocurred and proxy woke us up */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -38,36 +159,19 @@ Irq_session_component::Irq_session_component(Cap_session *cap_session,
|
|||||||
Range_allocator *irq_alloc,
|
Range_allocator *irq_alloc,
|
||||||
const char *args)
|
const char *args)
|
||||||
:
|
:
|
||||||
_irq_alloc(irq_alloc),
|
|
||||||
_ep(cap_session, STACK_SIZE, "irq")
|
_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 || !irq_alloc ||
|
|
||||||
irq_alloc->alloc_addr(1, irq_number) != Range_allocator::ALLOC_OK) {
|
/* check if IRQ thread was started before */
|
||||||
|
_proxy = Proxy::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc);
|
||||||
|
if (irq_number == -1 || !_proxy) {
|
||||||
PERR("Unavailable IRQ %lx requested", irq_number);
|
PERR("Unavailable IRQ %lx requested", irq_number);
|
||||||
throw Root::Invalid_args();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* alloc slector where IRQ will be mapped */
|
|
||||||
_irq_number = cap_selector_allocator()->alloc();
|
|
||||||
|
|
||||||
/* since we run in APIC mode translate IRQ 0 (PIT) to 2 */
|
|
||||||
if (!irq_number)
|
|
||||||
irq_number = 2;
|
|
||||||
|
|
||||||
/* map IRQ number to selector */
|
|
||||||
int ret = map_local((Nova::Utcb *)Thread_base::myself()->utcb(),
|
|
||||||
Nova::Obj_crd(platform_specific()->gsi_base_sel() + irq_number, 0),
|
|
||||||
Nova::Obj_crd(_irq_number, 0),
|
|
||||||
true);
|
|
||||||
if (ret) {
|
|
||||||
PERR("Could not map IRQ %d", _irq_number);
|
|
||||||
throw Root::Unavailable();
|
throw Root::Unavailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* assign IRQ to CPU */
|
_proxy->add_sharer();
|
||||||
enum { CPU = 0 };
|
|
||||||
Nova::assign_gsi(_irq_number, 0, CPU);
|
|
||||||
/* initialize capability */
|
/* initialize capability */
|
||||||
_irq_cap = _ep.manage(this);
|
_irq_cap = _ep.manage(this);
|
||||||
}
|
}
|
||||||
|
@ -134,24 +134,44 @@ static void page_fault_handler()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static addr_t core_pager_stack_top()
|
||||||
|
{
|
||||||
|
enum { STACK_SIZE = 4*1024 };
|
||||||
|
static char stack[STACK_SIZE];
|
||||||
|
return (addr_t)&stack[STACK_SIZE - sizeof(addr_t)];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Startup handler for core threads
|
||||||
|
*/
|
||||||
|
static void startup_handler()
|
||||||
|
{
|
||||||
|
Utcb *utcb = (Utcb *)CORE_PAGER_UTCB_ADDR;
|
||||||
|
|
||||||
|
/* initial IP is on stack */
|
||||||
|
utcb->ip = *reinterpret_cast<addr_t *>(utcb->sp);
|
||||||
|
utcb->mtd = Mtd::EIP | Mtd::ESP;
|
||||||
|
utcb->set_msg_word(0);
|
||||||
|
|
||||||
|
reply((void*)core_pager_stack_top());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void init_core_page_fault_handler()
|
static void init_core_page_fault_handler()
|
||||||
{
|
{
|
||||||
/* create echo EC */
|
/* create echo EC */
|
||||||
enum {
|
enum {
|
||||||
STACK_SIZE = 4*1024,
|
|
||||||
CPU_NO = 0,
|
CPU_NO = 0,
|
||||||
GLOBAL = false,
|
GLOBAL = false,
|
||||||
EXC_BASE = 0
|
EXC_BASE = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
static char stack[STACK_SIZE];
|
|
||||||
|
|
||||||
addr_t sp = (addr_t)&stack[STACK_SIZE - sizeof(addr_t)];
|
|
||||||
addr_t ec_sel = cap_selector_allocator()->alloc();
|
addr_t ec_sel = cap_selector_allocator()->alloc();
|
||||||
|
|
||||||
uint8_t ret = create_ec(ec_sel, __core_pd_sel, CPU_NO,
|
uint8_t ret = create_ec(ec_sel, __core_pd_sel, CPU_NO,
|
||||||
CORE_PAGER_UTCB_ADDR, (addr_t)sp, EXC_BASE,
|
CORE_PAGER_UTCB_ADDR, core_pager_stack_top(),
|
||||||
GLOBAL);
|
EXC_BASE, GLOBAL);
|
||||||
if (ret)
|
if (ret)
|
||||||
PDBG("create_ec returned %u", ret);
|
PDBG("create_ec returned %u", ret);
|
||||||
|
|
||||||
@ -159,6 +179,11 @@ static void init_core_page_fault_handler()
|
|||||||
create_pt(PT_SEL_PAGE_FAULT, __core_pd_sel, ec_sel,
|
create_pt(PT_SEL_PAGE_FAULT, __core_pd_sel, ec_sel,
|
||||||
Mtd(Mtd::QUAL | Mtd::ESP | Mtd::EIP),
|
Mtd(Mtd::QUAL | Mtd::ESP | Mtd::EIP),
|
||||||
(addr_t)page_fault_handler);
|
(addr_t)page_fault_handler);
|
||||||
|
|
||||||
|
/* startup portal for global core threads */
|
||||||
|
create_pt(PT_SEL_STARTUP, __core_pd_sel, ec_sel,
|
||||||
|
Mtd(Mtd::EIP | Mtd::ESP),
|
||||||
|
(addr_t)startup_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,13 +30,13 @@
|
|||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
|
||||||
|
|
||||||
/**
|
void Thread_base::_init_platform_thread()
|
||||||
|
{
|
||||||
|
/*
|
||||||
* This function is called for constructing server activations and pager
|
* This function is called for constructing server activations and pager
|
||||||
* objects. It allocates capability selectors for the thread's execution
|
* objects. It allocates capability selectors for the thread's execution
|
||||||
* context and a synchronization-helper semaphore needed for 'Lock'.
|
* context and a synchronization-helper semaphore needed for 'Lock'.
|
||||||
*/
|
*/
|
||||||
void Thread_base::_init_platform_thread()
|
|
||||||
{
|
|
||||||
using namespace Nova;
|
using namespace Nova;
|
||||||
|
|
||||||
_tid.ec_sel = cap_selector_allocator()->alloc();
|
_tid.ec_sel = cap_selector_allocator()->alloc();
|
||||||
@ -50,18 +50,6 @@ void Thread_base::_init_platform_thread()
|
|||||||
PERR("create_sm returned %u", res);
|
PERR("create_sm returned %u", res);
|
||||||
throw Cpu_session::Thread_creation_failed();
|
throw Cpu_session::Thread_creation_failed();
|
||||||
}
|
}
|
||||||
|
|
||||||
addr_t sp = reinterpret_cast<addr_t>(&_context->stack[-4]);
|
|
||||||
addr_t utcb = reinterpret_cast<addr_t>(&_context->utcb);
|
|
||||||
|
|
||||||
/* create local EC */
|
|
||||||
enum { CPU_NO = 0, GLOBAL = false };
|
|
||||||
res = create_ec(_tid.ec_sel, pd_sel, CPU_NO,
|
|
||||||
utcb, sp, _tid.exc_pt_sel, GLOBAL);
|
|
||||||
if (res != NOVA_OK) {
|
|
||||||
PERR("%p - create_ec returned %d", this, res);
|
|
||||||
throw Cpu_session::Thread_creation_failed();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -84,9 +72,25 @@ void Thread_base::_deinit_platform_thread()
|
|||||||
void Thread_base::start()
|
void Thread_base::start()
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* On NOVA, core never starts regular threads.
|
* On NOVA, core almost nerver starts regular threads. This simply creates a
|
||||||
|
* local EC
|
||||||
*/
|
*/
|
||||||
|
using namespace Nova;
|
||||||
|
|
||||||
|
addr_t sp = reinterpret_cast<addr_t>(&_context->stack[-4]);
|
||||||
|
addr_t utcb = reinterpret_cast<addr_t>(&_context->utcb);
|
||||||
|
addr_t pd_sel = Platform_pd::pd_core_sel();
|
||||||
|
|
||||||
|
/* create local EC */
|
||||||
|
enum { CPU_NO = 0, GLOBAL = false };
|
||||||
|
uint8_t res = create_ec(_tid.ec_sel, pd_sel, CPU_NO,
|
||||||
|
utcb, sp, _tid.exc_pt_sel, GLOBAL);
|
||||||
|
if (res != NOVA_OK) {
|
||||||
|
PERR("%p - create_ec returned %d", this, res);
|
||||||
|
throw Cpu_session::Thread_creation_failed();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread_base::cancel_blocking()
|
void Thread_base::cancel_blocking()
|
||||||
{
|
{
|
||||||
|
@ -12,14 +12,10 @@
|
|||||||
* under the terms of the GNU General Public License version 2.
|
* under the terms of the GNU General Public License version 2.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Genode includes */
|
#include <irq_proxy.h>
|
||||||
#include <base/printf.h>
|
|
||||||
#include <base/env.h>
|
|
||||||
#include <util/arg_string.h>
|
|
||||||
|
|
||||||
/* core includes */
|
/* core includes */
|
||||||
#include <irq_root.h>
|
#include <irq_root.h>
|
||||||
#include <util.h>
|
|
||||||
|
|
||||||
/* OKL4 includes */
|
/* OKL4 includes */
|
||||||
namespace Okl4 { extern "C" {
|
namespace Okl4 { extern "C" {
|
||||||
@ -30,8 +26,14 @@ namespace Okl4 { extern "C" {
|
|||||||
#include <l4/ipc.h>
|
#include <l4/ipc.h>
|
||||||
} }
|
} }
|
||||||
|
|
||||||
using namespace Genode;
|
|
||||||
using namespace Okl4;
|
using namespace Okl4;
|
||||||
|
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 */
|
||||||
@ -43,55 +45,12 @@ static inline Okl4::L4_ThreadId_t thread_get_my_global_id()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/******************************
|
/**
|
||||||
** Shared-interrupt support **
|
* Platform-specific proxy code
|
||||||
******************************/
|
|
||||||
|
|
||||||
class Irq_blocker : public List<Irq_blocker>::Element
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
Lock _wait_lock;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Irq_blocker() : _wait_lock(Lock::LOCKED) { }
|
|
||||||
|
|
||||||
void block() { _wait_lock.lock(); }
|
|
||||||
void unblock() { _wait_lock.unlock(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Proxy thread that associates to the interrupt and unblocks waiting irqctrl
|
|
||||||
* threads. Maybe, we should utilize our signals for interrupt delivery...
|
|
||||||
*
|
|
||||||
* XXX resources are not accounted as the interrupt is shared
|
|
||||||
*/
|
*/
|
||||||
class Irq_proxy : public Thread<0x1000>,
|
class Irq_proxy_component : public Proxy
|
||||||
public List<Irq_proxy>::Element
|
|
||||||
{
|
{
|
||||||
private:
|
protected:
|
||||||
|
|
||||||
char _name[32];
|
|
||||||
Lock _startup_lock;
|
|
||||||
|
|
||||||
long _irq_number;
|
|
||||||
|
|
||||||
Lock _mutex; /* protects this object */
|
|
||||||
int _num_sharers; /* number of clients sharing this IRQ */
|
|
||||||
Semaphore _sleep; /* wake me up if aspired blockers return */
|
|
||||||
List<Irq_blocker> _blocker_list;
|
|
||||||
int _num_blockers; /* number of currently blocked clients */
|
|
||||||
bool _woken_up; /* client decided to wake me up -
|
|
||||||
this prevents multiple wakeups
|
|
||||||
to happen during initialization */
|
|
||||||
|
|
||||||
const char *_construct_name(long irq_number)
|
|
||||||
{
|
|
||||||
snprintf(_name, sizeof(_name), "irqproxy%02lx", irq_number);
|
|
||||||
return _name;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _associate()
|
bool _associate()
|
||||||
{
|
{
|
||||||
@ -126,126 +85,28 @@ class Irq_proxy : public Thread<0x1000>,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _loop()
|
void _wait_for_irq()
|
||||||
{
|
{
|
||||||
/* wait for first blocker */
|
|
||||||
_sleep.down();
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
/* 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _ack_irq()
|
||||||
{
|
{
|
||||||
Lock::Guard lock_guard(_mutex);
|
|
||||||
|
|
||||||
/* 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,
|
|
||||||
* otherwise level-triggered interrupts will occur immediately
|
|
||||||
* after acknowledgement. That's an inherent security problem
|
|
||||||
* with shared IRQs and induces problems with dynamic driver
|
|
||||||
* load and unload.
|
|
||||||
*/
|
|
||||||
_sleep.down();
|
|
||||||
|
|
||||||
/* acknowledge previous interrupt */
|
|
||||||
L4_LoadMR(0, _irq_number);
|
L4_LoadMR(0, _irq_number);
|
||||||
L4_AcknowledgeInterrupt(0, 0);
|
L4_AcknowledgeInterrupt(0, 0);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Irq_proxy(long irq_number)
|
Irq_proxy_component(long irq_number) : Irq_proxy(irq_number)
|
||||||
:
|
|
||||||
Thread<0x1000>(_construct_name(irq_number)),
|
|
||||||
_startup_lock(Lock::LOCKED), _irq_number(irq_number),
|
|
||||||
_mutex(Lock::UNLOCKED), _num_sharers(0), _num_blockers(0), _woken_up(false)
|
|
||||||
{
|
{
|
||||||
start();
|
_start();
|
||||||
_startup_lock.lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Thread interface
|
|
||||||
*/
|
|
||||||
void entry()
|
|
||||||
{
|
|
||||||
if (_associate()) {
|
|
||||||
_startup_lock.unlock();
|
|
||||||
_loop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Block until interrupt occured
|
|
||||||
*/
|
|
||||||
void wait_for_irq()
|
|
||||||
{
|
|
||||||
Irq_blocker blocker;
|
|
||||||
{
|
|
||||||
Lock::Guard lock_guard(_mutex);
|
|
||||||
|
|
||||||
_blocker_list.insert(&blocker);
|
|
||||||
_num_blockers++;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The proxy thread is woken up if no client woke it up before
|
|
||||||
* and this client is the last aspired blocker.
|
|
||||||
*/
|
|
||||||
if (!_woken_up && _num_blockers == _num_sharers) {
|
|
||||||
_sleep.up();
|
|
||||||
_woken_up = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
blocker.block();
|
|
||||||
}
|
|
||||||
|
|
||||||
long irq_number() const { return _irq_number; }
|
|
||||||
|
|
||||||
void add_sharer()
|
|
||||||
{
|
|
||||||
Lock::Guard lock_guard(_mutex);
|
|
||||||
++_num_sharers;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static Irq_proxy *get_irq_proxy(long irq_number, Range_allocator *irq_alloc = 0)
|
|
||||||
{
|
|
||||||
static List<Irq_proxy> proxies;
|
|
||||||
static Lock proxies_lock;
|
|
||||||
|
|
||||||
Lock::Guard lock_guard(proxies_lock);
|
|
||||||
|
|
||||||
/* lookup proxy in database */
|
|
||||||
for (Irq_proxy *p = proxies.first(); p; p = p->next())
|
|
||||||
if (p->irq_number() == irq_number)
|
|
||||||
return p;
|
|
||||||
|
|
||||||
/* try to create proxy */
|
|
||||||
if (!irq_alloc || irq_alloc->alloc_addr(1, irq_number) != Range_allocator::ALLOC_OK)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
Irq_proxy *new_proxy = new (env()->heap()) Irq_proxy(irq_number);
|
|
||||||
proxies.insert(new_proxy);
|
|
||||||
|
|
||||||
return new_proxy;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***************************
|
/***************************
|
||||||
** IRQ session component **
|
** IRQ session component **
|
||||||
***************************/
|
***************************/
|
||||||
@ -259,7 +120,7 @@ bool Irq_session_component::Irq_control_component::associate_to_irq(unsigned irq
|
|||||||
void Irq_session_component::wait_for_irq()
|
void Irq_session_component::wait_for_irq()
|
||||||
{
|
{
|
||||||
/* block at interrupt proxy */
|
/* block at interrupt proxy */
|
||||||
Irq_proxy *p = get_irq_proxy(_irq_number);
|
Proxy *p = Proxy::get_irq_proxy<Irq_proxy_component>(_irq_number);
|
||||||
if (!p) {
|
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;
|
||||||
@ -293,7 +154,7 @@ Irq_session_component::Irq_session_component(Cap_session *cap_session,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* check if IRQ thread was started before */
|
/* check if IRQ thread was started before */
|
||||||
Irq_proxy *irq_proxy = get_irq_proxy(irq_number, irq_alloc);
|
Proxy *irq_proxy = Proxy::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc);
|
||||||
if (!irq_proxy) {
|
if (!irq_proxy) {
|
||||||
PERR("unavailable IRQ %lx requested", irq_number);
|
PERR("unavailable IRQ %lx requested", irq_number);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user