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_new_irq() { return 32; }
constexpr Call_arg call_id_delete_irq() { return 33; } constexpr Call_arg call_id_delete_irq() { return 33; }
constexpr Call_arg call_id_thread_quota() { return 34; } constexpr Call_arg call_id_thread_quota() { return 34; }
constexpr Call_arg call_id_ack_irq() { return 35; }
/** /**
* Create a domain * Create a domain
@ -376,6 +377,16 @@ namespace Kernel
return call(call_id_new_irq(), (Call_arg) p, irq_nr, signal_context_id); 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 * Destruct an interrupt object
* *

View File

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

View File

@ -245,6 +245,7 @@ class Kernel::Thread
void _call_route_thread_event(); void _call_route_thread_event();
void _call_new_irq(); void _call_new_irq();
void _call_delete_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() 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() { void Thread::_call_delete_irq() {
reinterpret_cast<User_irq*>(user_arg_1())->~User_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_pause_thread(): _call_pause_thread(); return;
case call_id_new_irq(): _call_new_irq(); return; case call_id_new_irq(): _call_new_irq(); return;
case call_id_delete_irq(): _call_delete_irq(); return; case call_id_delete_irq(): _call_delete_irq(); return;
case call_id_ack_irq(): _call_ack_irq(); return;
default: default:
PWRN("%s -> %s: unknown kernel call", pd_label(), label()); PWRN("%s -> %s: unknown kernel call", pd_label(), label());
_stop(); _stop();