mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-20 22:23:16 +00:00
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:
parent
e61a3db30d
commit
7c133add52
@ -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
|
||||||
*
|
*
|
||||||
|
@ -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_ */
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
|
||||||
/***************************
|
/***************************
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
Loading…
Reference in New Issue
Block a user