base: extend irq session to support MSIs
Works on base-nova and base-foc, the other kernels have no MSI support. Issue #1216
This commit is contained in:
parent
b0f900b32b
commit
d998df3b7f
|
@ -101,10 +101,13 @@ Irq_session_component::Irq_session_component(Range_allocator *irq_alloc,
|
||||||
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) {
|
if (irq_number == -1) {
|
||||||
PERR("invalid IRQ number requested");
|
PERR("invalid IRQ number requested");
|
||||||
|
|
||||||
throw Root::Unavailable();
|
throw Root::Unavailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long msi = Arg_string::find_arg(args, "device_config_phys").long_value(0);
|
||||||
|
if (msi)
|
||||||
|
throw Root::Unavailable();
|
||||||
|
|
||||||
/* check if IRQ thread was started before */
|
/* check if IRQ thread was started before */
|
||||||
_proxy = Irq_proxy_component::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc);
|
_proxy = Irq_proxy_component::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc);
|
||||||
if (!_proxy) {
|
if (!_proxy) {
|
||||||
|
@ -142,3 +145,10 @@ void Irq_session_component::sigh(Genode::Signal_context_capability sigh)
|
||||||
if (!old.valid() && sigh.valid())
|
if (!old.valid() && sigh.valid())
|
||||||
_proxy->add_sharer(&_irq_sigh);
|
_proxy->add_sharer(&_irq_sigh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Genode::Irq_session::Info Irq_session_component::info()
|
||||||
|
{
|
||||||
|
/* no MSI support */
|
||||||
|
return { .type = Genode::Irq_session::Info::Type::INVALID };
|
||||||
|
}
|
||||||
|
|
|
@ -135,10 +135,13 @@ Irq_session_component::Irq_session_component(Range_allocator *irq_alloc,
|
||||||
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) {
|
if (irq_number == -1) {
|
||||||
PERR("invalid IRQ number requested");
|
PERR("invalid IRQ number requested");
|
||||||
|
|
||||||
throw Root::Unavailable();
|
throw Root::Unavailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long msi = Arg_string::find_arg(args, "device_config_phys").long_value(0);
|
||||||
|
if (msi)
|
||||||
|
throw Root::Unavailable();
|
||||||
|
|
||||||
/* check if IRQ thread was started before */
|
/* check if IRQ thread was started before */
|
||||||
_proxy = Irq_proxy_component::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc);
|
_proxy = Irq_proxy_component::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc);
|
||||||
if (!_proxy) {
|
if (!_proxy) {
|
||||||
|
@ -176,3 +179,10 @@ void Irq_session_component::sigh(Genode::Signal_context_capability sigh)
|
||||||
if (!old.valid() && sigh.valid())
|
if (!old.valid() && sigh.valid())
|
||||||
_proxy->add_sharer(&_irq_sigh);
|
_proxy->add_sharer(&_irq_sigh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Genode::Irq_session::Info Irq_session_component::info()
|
||||||
|
{
|
||||||
|
/* no MSI support */
|
||||||
|
return { .type = Genode::Irq_session::Info::Type::INVALID };
|
||||||
|
}
|
||||||
|
|
|
@ -74,6 +74,10 @@ class Genode::Irq_proxy_component : public Irq_proxy_base
|
||||||
Irq_session::Trigger _trigger; /* interrupt trigger */
|
Irq_session::Trigger _trigger; /* interrupt trigger */
|
||||||
Irq_session::Polarity _polarity; /* interrupt polarity */
|
Irq_session::Polarity _polarity; /* interrupt polarity */
|
||||||
|
|
||||||
|
bool _running;
|
||||||
|
Genode::addr_t _msi_addr;
|
||||||
|
Genode::addr_t _msi_data;
|
||||||
|
|
||||||
Native_thread _capability() const { return _cap->kcap(); }
|
Native_thread _capability() const { return _cap->kcap(); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -81,18 +85,24 @@ class Genode::Irq_proxy_component : public Irq_proxy_base
|
||||||
bool _associate()
|
bool _associate()
|
||||||
{
|
{
|
||||||
using namespace Fiasco;
|
using namespace Fiasco;
|
||||||
if (l4_error(l4_factory_create_irq(L4_BASE_FACTORY_CAP, _capability()))) {
|
if (l4_error(l4_factory_create_irq(L4_BASE_FACTORY_CAP,
|
||||||
|
_capability()))) {
|
||||||
PERR("l4_factory_create_irq failed!");
|
PERR("l4_factory_create_irq failed!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (l4_error(l4_icu_bind(L4_BASE_ICU_CAP, _irq_number, _capability()))) {
|
unsigned long gsi = _irq_number;
|
||||||
|
if (_msi_addr)
|
||||||
|
gsi |= L4_ICU_FLAG_MSI;
|
||||||
|
|
||||||
|
if (l4_error(l4_icu_bind(L4_BASE_ICU_CAP, gsi, _capability()))) {
|
||||||
PERR("Binding IRQ%ld to the ICU failed", _irq_number);
|
PERR("Binding IRQ%ld to the ICU failed", _irq_number);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set interrupt mode */
|
if (!_msi_addr)
|
||||||
Platform::setup_irq_mode(_irq_number, _trigger, _polarity);
|
/* set interrupt mode */
|
||||||
|
Platform::setup_irq_mode(gsi, _trigger, _polarity);
|
||||||
|
|
||||||
if (l4_error(l4_irq_attach(_capability(), _irq_number,
|
if (l4_error(l4_irq_attach(_capability(), _irq_number,
|
||||||
Interrupt_handler::handler_cap()))) {
|
Interrupt_handler::handler_cap()))) {
|
||||||
|
@ -100,6 +110,12 @@ class Genode::Irq_proxy_component : public Irq_proxy_base
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_msi_addr && l4_error(l4_icu_msi_info(L4_BASE_ICU_CAP, gsi,
|
||||||
|
&_msi_data))) {
|
||||||
|
PERR("Error getting MSI info");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,10 +140,9 @@ class Genode::Irq_proxy_component : public Irq_proxy_base
|
||||||
Irq_proxy_base(irq_number),
|
Irq_proxy_base(irq_number),
|
||||||
_cap(cap_map()->insert(platform_specific()->cap_id_alloc()->alloc())),
|
_cap(cap_map()->insert(platform_specific()->cap_id_alloc()->alloc())),
|
||||||
_sem(), _trigger(Irq_session::TRIGGER_UNCHANGED),
|
_sem(), _trigger(Irq_session::TRIGGER_UNCHANGED),
|
||||||
_polarity(Irq_session::POLARITY_UNCHANGED)
|
_polarity(Irq_session::POLARITY_UNCHANGED),
|
||||||
{
|
_running(false), _msi_addr(0), _msi_data(0)
|
||||||
_start();
|
{ }
|
||||||
}
|
|
||||||
|
|
||||||
Semaphore *semaphore() { return &_sem; }
|
Semaphore *semaphore() { return &_sem; }
|
||||||
|
|
||||||
|
@ -142,6 +157,27 @@ class Genode::Irq_proxy_component : public Irq_proxy_base
|
||||||
/* set interrupt mode */
|
/* set interrupt mode */
|
||||||
Platform::setup_irq_mode(_irq_number, _trigger, _polarity);
|
Platform::setup_irq_mode(_irq_number, _trigger, _polarity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Genode::addr_t msi_address() const { return _msi_addr; }
|
||||||
|
Genode::addr_t msi_value() const { return _msi_data; }
|
||||||
|
|
||||||
|
void enable(bool msi)
|
||||||
|
{
|
||||||
|
if (_running)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (msi)
|
||||||
|
/*
|
||||||
|
* Local APIC address, See Intel x86 Spec - Section MSI 10.11.
|
||||||
|
*
|
||||||
|
* XXX local Apic ID encoding missing - address is constructed
|
||||||
|
* assuming that local APIC id of boot CPU is 0 XXX
|
||||||
|
*/
|
||||||
|
_msi_addr = 0xfee00000UL;
|
||||||
|
|
||||||
|
_running = true;
|
||||||
|
_start();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -165,8 +201,8 @@ Irq_session_component::Irq_session_component(Range_allocator *irq_alloc,
|
||||||
const char *args)
|
const char *args)
|
||||||
{
|
{
|
||||||
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) {
|
if (irq_number < 0) {
|
||||||
PERR("invalid IRQ number requested");
|
PERR("invalid IRQ number requested %ld", irq_number);
|
||||||
throw Root::Unavailable();
|
throw Root::Unavailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,12 +242,27 @@ Irq_session_component::Irq_session_component(Range_allocator *irq_alloc,
|
||||||
throw Root::Unavailable();
|
throw Root::Unavailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
long msi = Arg_string::find_arg(args, "device_config_phys").long_value(0);
|
||||||
* temporary hack for fiasco.oc using the local-apic,
|
if (msi) {
|
||||||
* where old pic-line 0 maps to 2
|
using namespace Fiasco;
|
||||||
*/
|
|
||||||
if (irq_number == 0)
|
l4_icu_info_t info { .features = 0 };
|
||||||
irq_number = 2;
|
l4_msgtag_t res = l4_icu_info(Fiasco::L4_BASE_ICU_CAP, &info);
|
||||||
|
if (l4_error(res) || !(info.features & L4_ICU_FLAG_MSI))
|
||||||
|
throw Root::Unavailable();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* irq_alloc range [0, max)
|
||||||
|
*
|
||||||
|
* legacy irq [0, max_legacy)
|
||||||
|
* msi [max_legacy, info.nr_msis)
|
||||||
|
* unused [info.nr_msis, max)
|
||||||
|
*
|
||||||
|
* max - is currently set to 256 in base-foc platform.cc
|
||||||
|
* max_legacy - is info.nr_irqs, defined by hardware/kernel
|
||||||
|
*/
|
||||||
|
irq_number = info.nr_msis - 1 - irq_number;
|
||||||
|
}
|
||||||
|
|
||||||
/* check if IRQ thread was started before */
|
/* check if IRQ thread was started before */
|
||||||
_proxy = Irq_proxy_component::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc);
|
_proxy = Irq_proxy_component::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc);
|
||||||
|
@ -222,7 +273,6 @@ Irq_session_component::Irq_session_component(Range_allocator *irq_alloc,
|
||||||
|
|
||||||
bool setup = false;
|
bool setup = false;
|
||||||
bool fail = false;
|
bool fail = false;
|
||||||
|
|
||||||
/* sanity check */
|
/* sanity check */
|
||||||
if (irq_trigger != TRIGGER_UNCHANGED && _proxy->trigger() != irq_trigger) {
|
if (irq_trigger != TRIGGER_UNCHANGED && _proxy->trigger() != irq_trigger) {
|
||||||
if (_proxy->trigger() == TRIGGER_UNCHANGED)
|
if (_proxy->trigger() == TRIGGER_UNCHANGED)
|
||||||
|
@ -251,6 +301,8 @@ Irq_session_component::Irq_session_component(Range_allocator *irq_alloc,
|
||||||
_proxy->setup_irq_mode(irq_trigger, irq_polarity);
|
_proxy->setup_irq_mode(irq_trigger, irq_polarity);
|
||||||
|
|
||||||
_irq_number = irq_number;
|
_irq_number = irq_number;
|
||||||
|
|
||||||
|
_proxy->enable(msi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -282,6 +334,19 @@ void Irq_session_component::sigh(Genode::Signal_context_capability sigh)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Genode::Irq_session::Info Irq_session_component::info()
|
||||||
|
{
|
||||||
|
if (!_proxy || !_proxy->msi_address() || !_proxy->msi_value())
|
||||||
|
return { .type = Genode::Irq_session::Info::Type::INVALID };
|
||||||
|
|
||||||
|
return {
|
||||||
|
.type = Genode::Irq_session::Info::Type::MSI,
|
||||||
|
.address = _proxy->msi_address(),
|
||||||
|
.value = _proxy->msi_value()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***************************************
|
/***************************************
|
||||||
** Interrupt handler implemtentation **
|
** Interrupt handler implemtentation **
|
||||||
***************************************/
|
***************************************/
|
||||||
|
|
|
@ -56,8 +56,10 @@ class Genode::Irq_session_component : public Rpc_object<Irq_session>,
|
||||||
** Irq session interface **
|
** Irq session interface **
|
||||||
***************************/
|
***************************/
|
||||||
|
|
||||||
void ack_irq();
|
void ack_irq() override;
|
||||||
void sigh(Signal_context_capability) override;
|
void sigh(Signal_context_capability) override;
|
||||||
|
Info info() override {
|
||||||
|
return { .type = Genode::Irq_session::Info::Type::INVALID }; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _INCLUDE__IRQ_SESSION_COMPONENT_H_ */
|
#endif /* _INCLUDE__IRQ_SESSION_COMPONENT_H_ */
|
||||||
|
|
|
@ -45,8 +45,10 @@ class Genode::Irq_session_component : public Rpc_object<Irq_session>,
|
||||||
** Irq session interface **
|
** Irq session interface **
|
||||||
***************************/
|
***************************/
|
||||||
|
|
||||||
void ack_irq() { }
|
void ack_irq() override { }
|
||||||
void sigh(Signal_context_capability) override { }
|
void sigh(Signal_context_capability) override { }
|
||||||
|
Info info() override {
|
||||||
|
return { .type = Genode::Irq_session::Info::Type::INVALID }; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _CORE__INCLUDE__LINUX__IRQ_SESSION_COMPONENT_H_ */
|
#endif /* _CORE__INCLUDE__LINUX__IRQ_SESSION_COMPONENT_H_ */
|
||||||
|
|
|
@ -120,45 +120,39 @@ class Genode::Irq_proxy_component : public Irq_proxy<Irq_thread>
|
||||||
|
|
||||||
Genode::addr_t _irq_sel; /* IRQ cap selector */
|
Genode::addr_t _irq_sel; /* IRQ cap selector */
|
||||||
Genode::addr_t _dev_mem; /* used when MSI or HPET is used */
|
Genode::addr_t _dev_mem; /* used when MSI or HPET is used */
|
||||||
|
bool _ready; /* flag to signal that IRQ SM can be used */
|
||||||
|
|
||||||
|
Genode::addr_t _msi_addr;
|
||||||
|
Genode::addr_t _msi_data;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
bool _associate()
|
bool _associate()
|
||||||
{
|
{
|
||||||
/* alloc slector where IRQ will be mapped */
|
/* assign IRQ to CPU && request msi data to be used by driver */
|
||||||
_irq_sel = cap_map()->insert();
|
|
||||||
|
|
||||||
/* 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 */
|
|
||||||
addr_t msi_addr = 0;
|
|
||||||
addr_t msi_data = 0;
|
|
||||||
uint8_t res = Nova::assign_gsi(_irq_sel, _dev_mem, boot_cpu(),
|
uint8_t res = Nova::assign_gsi(_irq_sel, _dev_mem, boot_cpu(),
|
||||||
msi_addr, msi_data);
|
_msi_addr, _msi_data);
|
||||||
if (res != Nova::NOVA_OK)
|
|
||||||
PERR("Error: assign_pci failed -irq:dev:msi_addr:msi_data "
|
|
||||||
"%lx:%lx:%lx:%lx", _irq_number, _dev_mem, msi_addr,
|
|
||||||
msi_data);
|
|
||||||
|
|
||||||
return res == Nova::NOVA_OK;
|
_ready = res == Nova::NOVA_OK;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return ever success so that the IRQ proxy thread gets started.
|
||||||
|
* For MSIs or HPET a separate associate() call with a valid
|
||||||
|
* dev_mem address is required.
|
||||||
|
*/
|
||||||
|
if (_dev_mem && !_ready)
|
||||||
|
PERR("setting up MSI 0x%lx failed - error %u", _irq_number, res);
|
||||||
|
|
||||||
|
return _dev_mem ? _ready : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _wait_for_irq()
|
void _wait_for_irq()
|
||||||
{
|
{
|
||||||
if (Nova::sm_ctrl(_irq_sel, Nova::SEMAPHORE_DOWN))
|
if (!_ready)
|
||||||
nova_die();
|
PERR("Error: assign_gsi failed for IRQ %ld", _irq_number);
|
||||||
|
|
||||||
|
if (Nova::NOVA_OK != Nova::sm_ctrl(_irq_sel, Nova::SEMAPHORE_DOWN))
|
||||||
|
PERR("Error: blocking for irq %ld failed", _irq_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _ack_irq() { }
|
void _ack_irq() { }
|
||||||
|
@ -167,13 +161,80 @@ class Genode::Irq_proxy_component : public Irq_proxy<Irq_thread>
|
||||||
|
|
||||||
Irq_proxy_component(long irq_number)
|
Irq_proxy_component(long irq_number)
|
||||||
:
|
:
|
||||||
Irq_proxy(irq_number), _dev_mem(0)
|
/* since we run in APIC mode translate IRQ 0 (PIT) to 2 */
|
||||||
|
Irq_proxy(irq_number ? irq_number : 2),
|
||||||
|
_irq_sel(cap_map()->insert()),
|
||||||
|
_dev_mem(0),
|
||||||
|
_ready(false),
|
||||||
|
_msi_addr(0),
|
||||||
|
_msi_data(0)
|
||||||
{
|
{
|
||||||
|
/* map IRQ SM cap from kernel to core at _irq_sel selector */
|
||||||
|
using Nova::Obj_crd;
|
||||||
|
|
||||||
|
Obj_crd src(platform_specific()->gsi_base_sel() + _irq_number, 0);
|
||||||
|
Obj_crd dst(_irq_sel, 0);
|
||||||
|
enum { MAP_FROM_KERNEL_TO_CORE = true };
|
||||||
|
|
||||||
|
int ret = map_local((Nova::Utcb *)Thread_base::myself()->utcb(),
|
||||||
|
src, dst, MAP_FROM_KERNEL_TO_CORE);
|
||||||
|
if (ret) {
|
||||||
|
PERR("Could not map IRQ %ld", _irq_number);
|
||||||
|
throw Root::Unavailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* let thread run */
|
||||||
_start();
|
_start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void associate(Genode::addr_t phys_mem)
|
||||||
|
{
|
||||||
|
void * v = 0;
|
||||||
|
if (platform()->region_alloc()->alloc_aligned(4096,
|
||||||
|
&v, 12).is_error())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Genode::addr_t virt_addr = reinterpret_cast<Genode::addr_t>(v);
|
||||||
|
|
||||||
|
if (!virt_addr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
using Nova::Mem_crd;
|
||||||
|
using Nova::Rights;
|
||||||
|
|
||||||
|
if (map_local_phys_to_virt(reinterpret_cast<Nova::Utcb *>(Thread_base::myself()->utcb()),
|
||||||
|
Mem_crd(phys_mem >> 12, 0, Rights(true, false, false)),
|
||||||
|
Mem_crd(virt_addr >> 12, 0, Rights(true, false, false)))) {
|
||||||
|
platform()->region_alloc()->free(v, 4096);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* local attached pci config extended io mem of device */
|
||||||
|
_dev_mem = virt_addr;
|
||||||
|
/* try to assign MSI to device */
|
||||||
|
_associate();
|
||||||
|
|
||||||
|
/* revert local mapping */
|
||||||
|
_dev_mem = 0;
|
||||||
|
unmap_local(Mem_crd(virt_addr >> 12, 0, Rights(true, true, true)));
|
||||||
|
platform()->region_alloc()->free(v, 4096);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ready() const { return _ready; }
|
||||||
|
Genode::addr_t msi_address() const { return _msi_addr; }
|
||||||
|
Genode::addr_t msi_value() const { return _msi_data; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static Nova::Hip * kernel_hip()
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Initial value of esp register, saved by the crt0 startup code.
|
||||||
|
* This value contains the address of the hypervisor information page.
|
||||||
|
*/
|
||||||
|
extern addr_t __initial_sp;
|
||||||
|
return reinterpret_cast<Nova::Hip *>(__initial_sp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***************************
|
/***************************
|
||||||
|
@ -195,20 +256,35 @@ void Irq_session_component::ack_irq()
|
||||||
Irq_session_component::Irq_session_component(Range_allocator *irq_alloc,
|
Irq_session_component::Irq_session_component(Range_allocator *irq_alloc,
|
||||||
const char *args)
|
const char *args)
|
||||||
{
|
{
|
||||||
|
typedef Irq_proxy<Irq_thread> Proxy;
|
||||||
|
|
||||||
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) {
|
if (irq_number < 0) {
|
||||||
PERR("invalid IRQ number requested");
|
PERR("invalid IRQ number requested");
|
||||||
throw Root::Unavailable();
|
throw Root::Unavailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long device_phys = Arg_string::find_arg(args, "device_config_phys").long_value(0);
|
||||||
|
if (device_phys) {
|
||||||
|
if (irq_number >= kernel_hip()->sel_gsi)
|
||||||
|
throw Root::Unavailable();
|
||||||
|
|
||||||
|
irq_number = kernel_hip()->sel_gsi - 1 - irq_number;
|
||||||
|
/* XXX last GSI number unknown - assume 40 GSIs (depends on IO-APIC) */
|
||||||
|
if (irq_number < 40)
|
||||||
|
throw Root::Unavailable();
|
||||||
|
}
|
||||||
|
|
||||||
/* check if IRQ thread was started before */
|
/* check if IRQ thread was started before */
|
||||||
typedef Irq_proxy<Irq_thread> Proxy;
|
|
||||||
_proxy = Proxy::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc);
|
_proxy = Proxy::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc);
|
||||||
if (!_proxy) {
|
if (!_proxy) {
|
||||||
PERR("unavailable IRQ %lx requested", irq_number);
|
PERR("unavailable IRQ %lx requested", irq_number);
|
||||||
throw Root::Unavailable();
|
throw Root::Unavailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (device_phys)
|
||||||
|
_proxy->associate(device_phys);
|
||||||
|
|
||||||
_irq_number = irq_number;
|
_irq_number = irq_number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,3 +316,17 @@ void Irq_session_component::sigh(Genode::Signal_context_capability sigh)
|
||||||
if (!old.valid() && sigh.valid())
|
if (!old.valid() && sigh.valid())
|
||||||
_proxy->add_sharer(&_irq_sigh);
|
_proxy->add_sharer(&_irq_sigh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Genode::Irq_session::Info Irq_session_component::info()
|
||||||
|
{
|
||||||
|
if (!_proxy || !_proxy->ready() || !_proxy->msi_address() ||
|
||||||
|
!_proxy->msi_value())
|
||||||
|
return { .type = Genode::Irq_session::Info::Type::INVALID };
|
||||||
|
|
||||||
|
return {
|
||||||
|
.type = Genode::Irq_session::Info::Type::MSI,
|
||||||
|
.address = _proxy->msi_address(),
|
||||||
|
.value = _proxy->msi_value()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -550,7 +550,7 @@ Platform::Platform() :
|
||||||
_io_port_alloc.add_range(0, 0x10000);
|
_io_port_alloc.add_range(0, 0x10000);
|
||||||
|
|
||||||
/* IRQ allocator */
|
/* IRQ allocator */
|
||||||
_irq_alloc.add_range(0, hip->sel_gsi - 1);
|
_irq_alloc.add_range(0, hip->sel_gsi);
|
||||||
_gsi_base_sel = (hip->mem_desc_offset - hip->cpu_desc_offset) / hip->cpu_desc_size;
|
_gsi_base_sel = (hip->mem_desc_offset - hip->cpu_desc_offset) / hip->cpu_desc_size;
|
||||||
|
|
||||||
if (verbose_boot_info) {
|
if (verbose_boot_info) {
|
||||||
|
|
|
@ -138,10 +138,13 @@ Irq_session_component::Irq_session_component(Range_allocator *irq_alloc,
|
||||||
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) {
|
if (irq_number == -1) {
|
||||||
PERR("invalid IRQ number requested");
|
PERR("invalid IRQ number requested");
|
||||||
|
|
||||||
throw Root::Unavailable();
|
throw Root::Unavailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long msi = Arg_string::find_arg(args, "device_config_phys").long_value(0);
|
||||||
|
if (msi)
|
||||||
|
throw Root::Unavailable();
|
||||||
|
|
||||||
/* check if IRQ thread was started before */
|
/* check if IRQ thread was started before */
|
||||||
_proxy = Irq_proxy_component::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc);
|
_proxy = Irq_proxy_component::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc);
|
||||||
if (!_proxy) {
|
if (!_proxy) {
|
||||||
|
@ -179,3 +182,10 @@ void Irq_session_component::sigh(Genode::Signal_context_capability sigh)
|
||||||
if (!old.valid() && sigh.valid())
|
if (!old.valid() && sigh.valid())
|
||||||
_proxy->add_sharer(&_irq_sigh);
|
_proxy->add_sharer(&_irq_sigh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Genode::Irq_session::Info Irq_session_component::info()
|
||||||
|
{
|
||||||
|
/* no MSI support */
|
||||||
|
return { .type = Genode::Irq_session::Info::Type::INVALID };
|
||||||
|
}
|
||||||
|
|
|
@ -157,10 +157,13 @@ Irq_session_component::Irq_session_component(Range_allocator *irq_alloc,
|
||||||
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) {
|
if (irq_number == -1) {
|
||||||
PERR("invalid IRQ number requested");
|
PERR("invalid IRQ number requested");
|
||||||
|
|
||||||
throw Root::Unavailable();
|
throw Root::Unavailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long msi = Arg_string::find_arg(args, "device_config_phys").long_value(0);
|
||||||
|
if (msi)
|
||||||
|
throw Root::Unavailable();
|
||||||
|
|
||||||
/* check if IRQ thread was started before */
|
/* check if IRQ thread was started before */
|
||||||
_proxy = Irq_proxy_component::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc);
|
_proxy = Irq_proxy_component::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc);
|
||||||
if (!_proxy) {
|
if (!_proxy) {
|
||||||
|
@ -198,3 +201,10 @@ void Irq_session_component::sigh(Genode::Signal_context_capability sigh)
|
||||||
if (!old.valid() && sigh.valid())
|
if (!old.valid() && sigh.valid())
|
||||||
_proxy->add_sharer(&_irq_sigh);
|
_proxy->add_sharer(&_irq_sigh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Genode::Irq_session::Info Irq_session_component::info()
|
||||||
|
{
|
||||||
|
/* no MSI support */
|
||||||
|
return { .type = Genode::Irq_session::Info::Type::INVALID };
|
||||||
|
}
|
||||||
|
|
|
@ -44,6 +44,8 @@ struct Genode::Irq_session_client : Rpc_client<Irq_session>
|
||||||
void ack_irq() override;
|
void ack_irq() override;
|
||||||
|
|
||||||
void sigh(Signal_context_capability sigh) override { call<Rpc_sigh>(sigh); }
|
void sigh(Signal_context_capability sigh) override { call<Rpc_sigh>(sigh); }
|
||||||
|
|
||||||
|
Info info() override { return call<Rpc_info>(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _INCLUDE__IRQ_SESSION__CLIENT_H_ */
|
#endif /* _INCLUDE__IRQ_SESSION__CLIENT_H_ */
|
||||||
|
|
|
@ -32,11 +32,13 @@ struct Genode::Irq_connection : Connection<Irq_session>, Irq_session_client
|
||||||
*/
|
*/
|
||||||
Irq_connection(unsigned irq,
|
Irq_connection(unsigned irq,
|
||||||
Irq_session::Trigger trigger = Irq_session::TRIGGER_UNCHANGED,
|
Irq_session::Trigger trigger = Irq_session::TRIGGER_UNCHANGED,
|
||||||
Irq_session::Polarity polarity = Irq_session::POLARITY_UNCHANGED)
|
Irq_session::Polarity polarity = Irq_session::POLARITY_UNCHANGED,
|
||||||
|
Genode::addr_t device_config_phys = 0)
|
||||||
:
|
:
|
||||||
Connection<Irq_session>(
|
Connection<Irq_session>(
|
||||||
session("ram_quota=4K, irq_number=%u, irq_trigger=%u, irq_polarity=%u",
|
session("ram_quota=4K, irq_number=%u, irq_trigger=%u, "
|
||||||
irq, trigger, polarity)),
|
" irq_polarity=%u, device_config_phys=0x%lx",
|
||||||
|
irq, trigger, polarity, device_config_phys)),
|
||||||
Irq_session_client(cap())
|
Irq_session_client(cap())
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,6 +32,12 @@ namespace Genode {
|
||||||
|
|
||||||
struct Genode::Irq_session : Session
|
struct Genode::Irq_session : Session
|
||||||
{
|
{
|
||||||
|
struct Info {
|
||||||
|
enum Type { INVALID, MSI } type;
|
||||||
|
unsigned long address;
|
||||||
|
unsigned long value;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interrupt trigger
|
* Interrupt trigger
|
||||||
*/
|
*/
|
||||||
|
@ -57,6 +63,12 @@ struct Genode::Irq_session : Session
|
||||||
*/
|
*/
|
||||||
virtual void sigh(Genode::Signal_context_capability sigh) = 0;
|
virtual void sigh(Genode::Signal_context_capability sigh) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request information about IRQ, e.g. on x86 request MSI address and
|
||||||
|
* MSI value to be programmed to device specific PCI registers.
|
||||||
|
*/
|
||||||
|
virtual Info info() = 0;
|
||||||
|
|
||||||
/*************
|
/*************
|
||||||
** Session **
|
** Session **
|
||||||
*************/
|
*************/
|
||||||
|
@ -70,7 +82,8 @@ struct Genode::Irq_session : Session
|
||||||
|
|
||||||
GENODE_RPC(Rpc_ack_irq, void, ack_irq);
|
GENODE_RPC(Rpc_ack_irq, void, ack_irq);
|
||||||
GENODE_RPC(Rpc_sigh, void, sigh, Genode::Signal_context_capability);
|
GENODE_RPC(Rpc_sigh, void, sigh, Genode::Signal_context_capability);
|
||||||
GENODE_RPC_INTERFACE(Rpc_ack_irq, Rpc_sigh);
|
GENODE_RPC(Rpc_info, Info, info);
|
||||||
|
GENODE_RPC_INTERFACE(Rpc_ack_irq, Rpc_sigh, Rpc_info);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _INCLUDE__IRQ_SESSION__IRQ_SESSION_H_ */
|
#endif /* _INCLUDE__IRQ_SESSION__IRQ_SESSION_H_ */
|
||||||
|
|
|
@ -57,8 +57,9 @@ class Genode::Irq_session_component : public Rpc_object<Irq_session>,
|
||||||
** Irq session interface **
|
** Irq session interface **
|
||||||
***************************/
|
***************************/
|
||||||
|
|
||||||
void ack_irq();
|
void ack_irq() override;
|
||||||
void sigh(Signal_context_capability) override;
|
void sigh(Signal_context_capability) override;
|
||||||
|
Info info() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_ */
|
#endif /* _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_ */
|
||||||
|
|
|
@ -46,6 +46,8 @@ class Gpio::Session_component : public Genode::Rpc_object<Gpio::Session>
|
||||||
void ack_irq() override { _driver.ack_irq(_pin); }
|
void ack_irq() override { _driver.ack_irq(_pin); }
|
||||||
void sigh(Genode::Signal_context_capability sigh) override {
|
void sigh(Genode::Signal_context_capability sigh) override {
|
||||||
_driver.register_signal(_pin, sigh); }
|
_driver.register_signal(_pin, sigh); }
|
||||||
|
Info info() override {
|
||||||
|
return { .type = Genode::Irq_session::Info::Type::INVALID }; }
|
||||||
};
|
};
|
||||||
|
|
||||||
Genode::Rpc_entrypoint &_ep;
|
Genode::Rpc_entrypoint &_ep;
|
||||||
|
|
|
@ -44,6 +44,8 @@ class Pci::Irq_session_component : public Genode::Rpc_object<Genode::Irq_session
|
||||||
** Irq session interface **
|
** Irq session interface **
|
||||||
***************************/
|
***************************/
|
||||||
|
|
||||||
void ack_irq() override;
|
void ack_irq() override;
|
||||||
void sigh(Genode::Signal_context_capability) override;
|
void sigh(Genode::Signal_context_capability) override;
|
||||||
|
Info info() override {
|
||||||
|
return { .type = Genode::Irq_session::Info::Type::INVALID }; }
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue