hw: acknowledge IRQs via Kernel::ack_irq

In the past, when the user blocked for an IRQ signal, the last signal was
acknowledged automatically thereby unmasking the IRQ. Now, the signal session
got a dedicated RPC for acknowledging IRQs and the HW back-end of that RPC
acknowledged the IRQ signal too. This led to the situation that IRQs were
unmasked twice. However, drivers expect an interrupt to be unmasked only on
the Irq_session::ack_irq and thus IRQ unmasking was moved from
Kernel::ack_signal to a dedicated kernel call.

Fixes #1493
This commit is contained in:
Martin Stein 2015-04-28 12:56:59 +02:00 committed by Christian Helmuth
parent e61a3db30d
commit 7c133add52
5 changed files with 32 additions and 31 deletions

View File

@ -58,6 +58,7 @@ namespace Kernel
constexpr Call_arg call_id_new_irq() { return 32; }
constexpr Call_arg call_id_delete_irq() { return 33; }
constexpr Call_arg call_id_thread_quota() { return 34; }
constexpr Call_arg call_id_ack_irq() { return 35; }
/**
* Create a domain
@ -376,6 +377,16 @@ namespace Kernel
return call(call_id_new_irq(), (Call_arg) p, irq_nr, signal_context_id);
}
/**
* Acknowledge interrupt
*
* \param irq pointer to interrupt kernel object
*/
inline void ack_irq(User_irq * const irq)
{
call(call_id_ack_irq(), (Call_arg) irq);
}
/**
* Destruct an interrupt object
*

View File

@ -90,10 +90,7 @@ class Kernel::Irq : public Object_pool<Irq>::Item
};
class Kernel::User_irq
:
public Kernel::Irq,
public Signal_ack_handler
class Kernel::User_irq : public Kernel::Irq
{
private:
@ -104,32 +101,18 @@ class Kernel::User_irq
*/
static Irq::Pool * _pool();
/************************
** Signal_ack_handler **
************************/
void _signal_acknowledged() { enable(); }
public:
/**
* Constructor
*
* \param irq_id kernel name of the interrupt
* Construct object that signals interrupt 'irq' via signal 'context'
*/
User_irq(unsigned const irq_id, Signal_context &context)
: Irq(irq_id, *_pool()), _context(context)
{
disable();
_context.ack_handler(this);
}
User_irq(unsigned const irq, Signal_context &context)
: Irq(irq, *_pool()), _context(context) { disable(); }
~User_irq()
{
_context.ack_handler(nullptr);
disable();
}
/**
* Destructor
*/
~User_irq() { disable(); }
/**
* Handle occurence of the interrupt
@ -141,12 +124,10 @@ class Kernel::User_irq
}
/**
* Handle occurence of an interrupt
*
* \param irq_id kernel name of targeted interrupt
* Handle occurence of interrupt 'irq'
*/
static User_irq * object(unsigned const irq_id) {
return dynamic_cast<User_irq*>(_pool()->object(irq_id)); }
static User_irq * object(unsigned const irq) {
return dynamic_cast<User_irq*>(_pool()->object(irq)); }
};
#endif /* _KERNEL__IRQ_H_ */

View File

@ -245,6 +245,7 @@ class Kernel::Thread
void _call_route_thread_event();
void _call_new_irq();
void _call_delete_irq();
void _call_ack_irq();
/***************************

View File

@ -31,7 +31,10 @@ unsigned Irq_session_component::_find_irq_number(const char * const args)
void Irq_session_component::ack_irq()
{
Kernel::ack_signal(_sig_cap.dst());
using Kernel::User_irq;
if (!_sig_cap.valid()) { return; }
User_irq * const kirq = reinterpret_cast<User_irq*>(&_kernel_object);
Kernel::ack_irq(kirq);
}

View File

@ -713,6 +713,10 @@ void Thread::_call_new_irq()
}
void Thread::_call_ack_irq() {
reinterpret_cast<User_irq*>(user_arg_1())->enable(); }
void Thread::_call_delete_irq() {
reinterpret_cast<User_irq*>(user_arg_1())->~User_irq(); }
@ -794,6 +798,7 @@ void Thread::_call()
case call_id_pause_thread(): _call_pause_thread(); return;
case call_id_new_irq(): _call_new_irq(); return;
case call_id_delete_irq(): _call_delete_irq(); return;
case call_id_ack_irq(): _call_ack_irq(); return;
default:
PWRN("%s -> %s: unknown kernel call", pd_label(), label());
_stop();