hw: IRQ receiver in extra header & reviewed

ref #528
This commit is contained in:
Martin Stein 2013-09-05 12:47:19 +02:00 committed by Norman Feske
parent 2c357a4f04
commit 01e8ee2752
3 changed files with 171 additions and 139 deletions

View File

@ -341,64 +341,8 @@ namespace Kernel
Tlb * const tlb() { return _tlb; }
Platform_pd * const platform_pd() { return _platform_pd; }
};
/**
* Access to static interrupt-controller
*/
static Pic * pic() { return unsynchronized_singleton<Pic>(); }
}
bool Kernel::Irq_owner::allocate_irq(unsigned const irq)
{
/* Check if an allocation is needed and possible */
unsigned const id = irq_to_id(irq);
if (_id) return _id == id;
if (_pool()->object(id)) return 0;
/* Let us own the IRQ, but mask it till we await it */
pic()->mask(irq);
_id = id;
_pool()->insert(this);
return 1;
}
bool Kernel::Irq_owner::free_irq(unsigned const irq)
{
if (_id != irq_to_id(irq)) return 0;
_pool()->remove(this);
_id = 0;
return 1;
}
void Kernel::Irq_owner::await_irq()
{
assert(_id);
unsigned const irq = id_to_irq(_id);
pic()->unmask(irq);
_awaits_irq();
}
void Kernel::Irq_owner::cancel_waiting() {
if (_id) pic()->mask(id_to_irq(_id)); }
void Kernel::Irq_owner::receive_irq(unsigned const irq)
{
assert(_id == irq_to_id(irq));
pic()->mask(irq);
_received_irq();
}
Kernel::Irq_owner * Kernel::Irq_owner::owner(unsigned irq) {
return _pool()->object(irq_to_id(irq)); }
namespace Kernel
{
/**
@ -837,8 +781,7 @@ namespace Kernel
default: {
/* IRQ not owned by core, thus notify IRQ owner */
Irq_owner * const o = Irq_owner::owner(irq);
Irq_receiver * const o = Irq_receiver::receiver(irq);
assert(o);
o->receive_irq(irq);
break; }
@ -1521,7 +1464,7 @@ int Kernel::Thread::resume()
return 0;
case AWAIT_IRQ:
PDBG("cancel IRQ receipt");
Irq_owner::cancel_waiting();
Irq_receiver::cancel_waiting();
_schedule();
return 0;
case AWAIT_SIGNAL:

View File

@ -0,0 +1,167 @@
/*
* \brief Exclusive ownership and handling of interrupts
* \author Martin Stein
* \date 2012-11-30
*/
/*
* 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 _KERNEL__IRQ_RECEIVER_H_
#define _KERNEL__IRQ_RECEIVER_H_
/* core includes */
#include <pic.h>
#include <assert.h>
#include <kernel/object.h>
namespace Kernel
{
/**
* Exclusive ownership and handling of one interrupt at a time
*/
class Irq_receiver;
/**
* Return interrupt-controller singleton
*/
static Pic * pic() { return unsynchronized_singleton<Pic>(); }
}
class Kernel::Irq_receiver : public Object_pool<Irq_receiver>::Item
{
private:
typedef Object_pool<Irq_receiver> Pool;
/**
* Return map that maps assigned interrupts to their receivers
*/
static Pool * _pool() { static Pool _pool; return &_pool; }
/**
* Translate receiver ID 'id' to interrupt ID
*/
static unsigned _id_to_irq(unsigned id) { return id - 1; }
/**
* Translate interrupt ID 'id' to receiver ID
*/
static unsigned _irq_to_id(unsigned irq) { return irq + 1; }
/**
* Free interrupt of this receiver without sanity checks
*/
void _free_irq()
{
_pool()->remove(this);
_id = 0;
}
/**
* Stop receiver from waiting for its interrupt without sanity checks
*/
void _cancel_waiting() { pic()->mask(_id_to_irq(_id)); }
/**
* Gets called as soon as the receivers interrupt occurs
*/
virtual void _received_irq() = 0;
/**
* Gets called when receiver starts waiting for its interrupt
*/
virtual void _awaits_irq() = 0;
public:
/**
* Constructor
*/
Irq_receiver() : Pool::Item(0) { }
/**
* Destructor
*/
~Irq_receiver()
{
if (_id) {
_cancel_waiting();
_free_irq();
}
}
/**
* Assign interrupt 'irq' to the receiver
*
* \return wether the assignment succeeded
*/
bool allocate_irq(unsigned const irq)
{
/* check if an allocation is needed and possible */
unsigned const id = _irq_to_id(irq);
if (_id) { return _id == id; }
if (_pool()->object(id)) { return 0; }
/* allocate and mask the interrupt */
pic()->mask(irq);
_id = id;
_pool()->insert(this);
return 1;
}
/**
* Unassign interrupt 'irq' if it is assigned to the receiver
*
* \return wether the unassignment succeeded
*/
bool free_irq(unsigned const irq)
{
if (_id != _irq_to_id(irq)) { return 0; }
_free_irq();
return 1;
}
/**
* Unmask and await interrupt that is assigned to the receiver
*/
void await_irq()
{
if (!_id) {
PERR("waiting for imaginary interrupt");
return;
}
unsigned const irq = _id_to_irq(_id);
pic()->unmask(irq);
_awaits_irq();
}
/**
* Stop waiting for the interrupt of the receiver
*/
void cancel_waiting() { if (_id) { _cancel_waiting(); } }
/**
* Denote that the receivers interrupt 'irq' occured and mask it
*/
void receive_irq(unsigned const irq)
{
assert(_id == _irq_to_id(irq));
pic()->mask(irq);
_received_irq();
}
/**
* Get receiver of IRQ 'irq' or 0 if the IRQ isn't assigned
*/
static Irq_receiver * receiver(unsigned irq)
{
return _pool()->object(_irq_to_id(irq));
}
};
#endif /* _KERNEL__IRQ_RECEIVER_H_ */

View File

@ -20,12 +20,12 @@
/* core includes */
#include <cpu.h>
#include <tlb.h>
#include <pic.h>
#include <timer.h>
#include <assert.h>
#include <kernel/configuration.h>
#include <kernel/scheduler.h>
#include <kernel/object.h>
#include <kernel/irq_receiver.h>
namespace Genode
{
@ -234,84 +234,6 @@ namespace Kernel
void cancel_waiting();
};
/**
* Exclusive ownership and handling of one IRQ per instance at a max
*/
class Irq_owner : public Object_pool<Irq_owner>::Item
{
/**
* To get any instance of this class by its ID
*/
typedef Object_pool<Irq_owner> Pool;
static Pool * _pool() { static Pool _pool; return &_pool; }
/**
* Is called when the IRQ we were waiting for has occured
*/
virtual void _received_irq() = 0;
/**
* Is called when we start waiting for the occurence of an IRQ
*/
virtual void _awaits_irq() = 0;
public:
/**
* Translate 'Irq_owner_pool'-item ID to IRQ ID
*/
static unsigned id_to_irq(unsigned id) { return id - 1; }
/**
* Translate IRQ ID to 'Irq_owner_pool'-item ID
*/
static unsigned irq_to_id(unsigned irq) { return irq + 1; }
/**
* Constructor
*/
Irq_owner() : Pool::Item(0) { }
/**
* Destructor
*/
virtual ~Irq_owner() { }
/**
* Ensure that our 'receive_irq' gets called on IRQ 'irq'
*
* \return wether the IRQ is allocated to the caller or not
*/
bool allocate_irq(unsigned const irq);
/**
* Release the ownership of the IRQ 'irq' if we own it
*
* \return wether the IRQ is freed or not
*/
bool free_irq(unsigned const irq);
/**
* If we own an IRQ, enable it and await 'receive_irq'
*/
void await_irq();
/**
* Stop waiting for an IRQ if in a waiting state
*/
void cancel_waiting();
/**
* Denote occurence of an IRQ if we own it and awaited it
*/
void receive_irq(unsigned const irq);
/**
* Get owner of IRQ or 0 if the IRQ is not owned by anyone
*/
static Irq_owner * owner(unsigned irq);
};
/**
* Kernel representation of a user thread
*/
@ -320,7 +242,7 @@ namespace Kernel
public Schedule_context,
public Fifo<Thread>::Element,
public Ipc_node,
public Irq_owner
public Irq_receiver
{
enum State
{