base: add irq_type session argument

By adding the `irq_type` argument, one can explicitly specify whether to
use LEGACY, MSI or MSI-X interrupts. We formerly used the
`device_phys_config` to implicitly select MSI, however, with the
addition of IOMMU support to the platform driver there is at least one
instance where we need an MSI for a non-PCI device.

Yet, by adding another session argument to the Irq session, we exceed
the character limit for session args. Since not all arguments are
relevant for LEGACY interrupts resp. MSI, we can split the Irq_connection
constructor to handle the two cases separately and omit unneeded
arguments.

genodelabs/genode#5002
This commit is contained in:
Johannes Schlatow 2023-10-03 15:37:01 +02:00
parent a80464299a
commit eefaa07024
16 changed files with 88 additions and 42 deletions

View File

@ -16,6 +16,7 @@
/* core includes */
#include <irq_root.h>
#include <irq_args.h>
#include <util.h>
/* L4/Fiasco includes */
@ -125,7 +126,9 @@ Irq_session_component::Irq_session_component(Range_allocator &irq_alloc,
_irq_alloc(irq_alloc),
_irq_object(_irq_number)
{
long msi = Arg_string::find_arg(args, "device_config_phys").long_value(0);
Irq_args irq_args(args);
bool msi { irq_args.type() != Irq_session::TYPE_LEGACY };
if (msi)
throw Service_denied();

View File

@ -193,7 +193,8 @@ Irq_session_component::Irq_session_component(Range_allocator &irq_alloc,
_irq_number((unsigned)Arg_string::find_arg(args, "irq_number").long_value(-1)),
_irq_alloc(irq_alloc), _irq_object()
{
long const msi = Arg_string::find_arg(args, "device_config_phys").long_value(0);
Irq_args const irq_args(args);
bool msi { irq_args.type() != TYPE_LEGACY };
if (msi) {
if (msi_alloc().get(_irq_number, 1)) {
@ -208,8 +209,6 @@ Irq_session_component::Irq_session_component(Range_allocator &irq_alloc,
}
}
Irq_args const irq_args(args);
if (_irq_object.associate(_irq_number, msi, irq_args.trigger(),
irq_args.polarity()))
return;

View File

@ -69,10 +69,7 @@ Irq_session_component::Irq_session_component(Range_allocator &irq_alloc,
_irq_number((unsigned)Platform::irq(_irq_args.irq_number())),
_irq_alloc(irq_alloc), _kobj(), _is_msi(false), _address(0), _value(0)
{
long const mmconf =
Arg_string::find_arg(args, "device_config_phys").long_value(0);
if (mmconf) {
if (_irq_args.type() != Irq_session::TYPE_LEGACY) {
_is_msi = Platform::alloc_msi_vector(_address, _value);
if (!_is_msi)
throw Service_denied();

View File

@ -115,7 +115,7 @@ void Irq_object::sigh(Signal_context_capability cap)
/* associate GSI or MSI to device belonging to device_phys */
bool ok = false;
if (_device_phys)
if (_device_phys || (_msi_addr && _msi_data))
ok = associate_msi(irq_sel(), _device_phys, _msi_addr, _msi_data, cap);
else
ok = associate_gsi(irq_sel(), cap, _gsi_flags);
@ -173,10 +173,10 @@ void Irq_object::start(unsigned irq, addr_t const device_phys, Irq_args const &i
/* associate GSI or MSI to device belonging to device_phys */
bool ok = false;
if (device_phys)
ok = associate_msi(irq_sel(), device_phys, _msi_addr, _msi_data, _sigh_cap);
else
if (irq_args.type() == Irq_session::TYPE_LEGACY)
ok = associate_gsi(irq_sel(), _sigh_cap, _gsi_flags);
else
ok = associate_msi(irq_sel(), device_phys, _msi_addr, _msi_data, _sigh_cap);
if (!ok)
throw Service_denied();
@ -217,8 +217,7 @@ Irq_session_component::Irq_session_component(Range_allocator &irq_alloc,
Irq_args const irq_args(args);
long irq_number = irq_args.irq_number();
long device_phys = Arg_string::find_arg(args, "device_config_phys").long_value(0);
if (device_phys) {
if (irq_args.type() != Irq_session::TYPE_LEGACY) {
if ((unsigned long)irq_number >= kernel_hip().sel_gsi)
throw Service_denied();
@ -236,6 +235,7 @@ Irq_session_component::Irq_session_component(Range_allocator &irq_alloc,
_irq_number = (unsigned)irq_number;
long device_phys = Arg_string::find_arg(args, "device_config_phys").long_value(0);
_irq_object.start(_irq_number, device_phys, irq_args);
}

View File

@ -17,6 +17,7 @@
/* core includes */
#include <irq_root.h>
#include <irq_args.h>
#include <irq_session_component.h>
/* base-internal includes */
@ -133,7 +134,8 @@ Irq_session_component::Irq_session_component(Range_allocator &irq_alloc,
_irq_alloc(irq_alloc),
_irq_object(_irq_number)
{
long msi = Arg_string::find_arg(args, "device_config_phys").long_value(0);
Irq_args irq_args(args);
bool msi { irq_args.type() != Irq_session::TYPE_LEGACY };
if (msi)
throw Service_denied();

View File

@ -16,6 +16,7 @@
/* core includes */
#include <irq_root.h>
#include <irq_args.h>
#include <util.h>
using namespace Core;
@ -126,7 +127,8 @@ Irq_session_component::Irq_session_component(Range_allocator &irq_alloc,
_irq_alloc(irq_alloc),
_irq_object(_irq_number)
{
long msi = Arg_string::find_arg(args, "device_config_phys").long_value(0);
Irq_args irq_args(args);
bool msi { irq_args.type() != Irq_session::TYPE_LEGACY };
if (msi)
throw Service_denied();

View File

@ -103,7 +103,8 @@ Irq_session_component::Irq_session_component(Range_allocator &irq_alloc,
_irq_alloc(irq_alloc),
_irq_object(_irq_number)
{
long msi = Arg_string::find_arg(args, "device_config_phys").long_value(0);
Irq_args const irq_args(args);
bool msi { irq_args.type() != Irq_session::TYPE_LEGACY };
if (msi)
throw Service_denied();
@ -113,8 +114,6 @@ Irq_session_component::Irq_session_component(Range_allocator &irq_alloc,
}
Irq_args const irq_args(args);
if (!_irq_object.associate(irq_args.trigger(), irq_args.polarity())) {
error("could not associate with IRQ ", irq_args.irq_number());
throw Service_denied();

View File

@ -32,14 +32,32 @@ struct Genode::Irq_connection : Connection<Irq_session>, Irq_session_client
Irq_connection(Env &env,
Label const &label,
Trigger trigger = Irq_session::TRIGGER_UNCHANGED,
Polarity polarity = Irq_session::POLARITY_UNCHANGED,
addr_t device_config_phys = 0)
Polarity polarity = Irq_session::POLARITY_UNCHANGED)
:
Connection<Irq_session>(env, label, Ram_quota { RAM_QUOTA },
Args("irq_number=", label, ", "
"irq_trigger=", unsigned(trigger), ", "
"irq_polarity=", unsigned(polarity), ", "
"device_config_phys=", Hex(device_config_phys))),
"irq_type=", unsigned(TYPE_LEGACY))),
Irq_session_client(cap())
{ }
/**
* Constructor
*
* \param label (virtual) interrupt number
* \param device_config_phys config-space physical address
* \param type interrupt type (e.g., msi/msi-x)
*/
Irq_connection(Env &env,
Label const &label,
addr_t device_config_phys,
Type type = Irq_session::TYPE_MSI)
:
Connection<Irq_session>(env, label, Ram_quota { RAM_QUOTA },
Args("irq_number=", label, ", "
"device_config_phys=", Hex(device_config_phys), ", "
"irq_type=", unsigned(type))),
Irq_session_client(cap())
{ }
};

View File

@ -48,6 +48,11 @@ struct Genode::Irq_session : Session
*/
enum Polarity { POLARITY_UNCHANGED = 0, POLARITY_HIGH, POLARITY_LOW };
/**
* Interrupt type
*/
enum Type { TYPE_LEGACY = 0, TYPE_MSI, TYPE_MSIX };
/**
* Destructor
*/

View File

@ -29,6 +29,7 @@ class Core::Irq_args
Irq_session::Trigger _irq_trigger { Irq_session::TRIGGER_UNCHANGED };
Irq_session::Polarity _irq_polarity { Irq_session::POLARITY_UNCHANGED };
Irq_session::Type _irq_type { Irq_session::TYPE_LEGACY };
long const _irq_number;
@ -38,8 +39,9 @@ class Core::Irq_args
:
_irq_number(Arg_string::find_arg(args, "irq_number").long_value(-1))
{
long irq_trg = Arg_string::find_arg(args, "irq_trigger").long_value(-1);
long irq_pol = Arg_string::find_arg(args, "irq_polarity").long_value(-1);
long irq_trg = Arg_string::find_arg(args, "irq_trigger").long_value(-1);
long irq_pol = Arg_string::find_arg(args, "irq_polarity").long_value(-1);
long irq_type = Arg_string::find_arg(args, "irq_type").long_value(-1);
switch (irq_trg) {
case -1:
@ -74,11 +76,29 @@ class Core::Irq_args
_irq_number);
throw Service_denied();
}
switch (irq_type) {
case -1:
case Irq_session::TYPE_LEGACY:
_irq_type = Irq_session::TYPE_LEGACY;
break;
case Irq_session::TYPE_MSI:
_irq_type = Irq_session::TYPE_MSI;
break;
case Irq_session::TYPE_MSIX:
_irq_type = Irq_session::TYPE_MSIX;
break;
default:
error("invalid type ", irq_type, " specified for IRQ ",
_irq_number);
throw Service_denied();
}
}
long irq_number() const { return _irq_number; }
Irq_session::Trigger trigger() const { return _irq_trigger; }
Irq_session::Polarity polarity() const { return _irq_polarity; }
Irq_session::Type type() const { return _irq_type; }
};
#endif /* _CORE__INCLUDE__IRQ_ARGS_H_ */

View File

@ -207,7 +207,8 @@ void Driver::Device::update(Allocator &alloc, Xml_node const &node)
irq.mode = (mode == "edge") ? Irq_session::TRIGGER_EDGE
: Irq_session::TRIGGER_LEVEL;
if (type.valid())
irq.type = (type == "msi-x") ? Irq::MSIX : Irq::MSI;
irq.type = (type == "msi-x") ? Irq_session::TYPE_MSIX
: Irq_session::TYPE_MSI;
return irq;
},
@ -463,7 +464,7 @@ void Driver::Device_model::update(Xml_node const & node)
for_each([&] (Device const & device) {
device._irq_list.for_each([&] (Device::Irq const & irq) {
if (irq.type != Device::Irq::LEGACY)
if (irq.type != Irq_session::TYPE_LEGACY)
return;
if (detected_irqs.get(irq.number, 1)) {
@ -480,7 +481,7 @@ void Driver::Device_model::update(Xml_node const & node)
for_each([&] (Device & device) {
device._irq_list.for_each([&] (Device::Irq & irq) {
if (irq.type != Device::Irq::LEGACY)
if (irq.type != Irq_session::TYPE_LEGACY)
return;
if (shared_irqs.get(irq.number, 1))

View File

@ -97,10 +97,8 @@ class Driver::Device : private List_model<Device>::Element
struct Irq : List_model<Irq>::Element
{
enum Type { LEGACY, MSI, MSIX };
unsigned number;
Type type { LEGACY };
Irq_session::Type type { Irq_session::TYPE_LEGACY };
Irq_session::Polarity polarity { Irq_session::POLARITY_UNCHANGED };
Irq_session::Trigger mode { Irq_session::TRIGGER_UNCHANGED };
bool shared { false };

View File

@ -104,15 +104,17 @@ Genode::Irq_session_capability Device_component::irq(unsigned idx)
if (!irq.shared && !irq.irq.constructed()) {
addr_t pci_cfg_addr = 0;
if (irq.type != Device::Irq::LEGACY) {
if (irq.type != Irq_session::TYPE_LEGACY) {
if (_pci_config.constructed()) pci_cfg_addr = _pci_config->addr;
else
error("MSI(-x) detected for device without pci-config!");
}
irq.irq.construct(_env, irq.number, irq.mode, irq.polarity,
pci_cfg_addr);
irq.irq.construct(_env, irq.number, pci_cfg_addr, irq.type);
} else
irq.irq.construct(_env, irq.number, irq.mode, irq.polarity);
Irq_session::Info info = irq.irq->info();
if (info.type == Irq_session::Info::MSI)
if (pci_cfg_addr && info.type == Irq_session::Info::MSI)
pci_msi_enable(_env, *this, pci_cfg_addr, info, irq.type);
}
@ -179,7 +181,7 @@ Device_component::Device_component(Registry<Device_component> & registry,
try {
device.for_each_irq([&] (unsigned idx,
unsigned nr,
Device::Irq::Type type,
Irq_session::Type type,
Irq_session::Polarity polarity,
Irq_session::Trigger mode,
bool shared)

View File

@ -40,7 +40,7 @@ class Driver::Device_component : public Rpc_object<Platform::Device_interface,
{
unsigned idx;
unsigned number;
Device::Irq::Type type;
Irq_session::Type type;
Irq_session::Polarity polarity;
Irq_session::Trigger mode;
bool shared;
@ -50,7 +50,7 @@ class Driver::Device_component : public Rpc_object<Platform::Device_interface,
Irq(Registry<Irq> & registry,
unsigned idx,
unsigned number,
Device::Irq::Type type,
Irq_session::Type type,
Irq_session::Polarity polarity,
Irq_session::Trigger mode,
bool shared)

View File

@ -193,13 +193,13 @@ void Driver::pci_msi_enable(Env & env,
Device_component & dc,
addr_t cfg_space,
Irq_session::Info const info,
Device::Irq::Type type)
Irq_session::Type type)
{
Attached_io_mem_dataspace io_mem { env, cfg_space, 0x1000 };
Config config { (addr_t)io_mem.local_addr<void>() };
config.scan();
if (type == Device::Irq::Type::MSIX && config.msi_x_cap.constructed()) {
if (type == Irq_session::TYPE_MSIX && config.msi_x_cap.constructed()) {
try {
/* find the MSI-x table from the device's memory bars */
Platform::Device_interface::Range range;
@ -231,7 +231,7 @@ void Driver::pci_msi_enable(Env & env,
return;
}
if (type == Device::Irq::Type::MSI && config.msi_cap.constructed()) {
if (type == Irq_session::TYPE_MSI && config.msi_cap.constructed()) {
config.msi_cap->enable(info.address, (uint16_t)info.value);
return;
}

View File

@ -36,7 +36,7 @@ namespace Driver {
void pci_apply_quirks(Genode::Env & env, Device const & dev);
void pci_msi_enable(Genode::Env & env, Device_component & dc,
addr_t cfg_space, Genode::Irq_session::Info const info,
Device::Irq::Type type);
Irq_session::Type type);
bool pci_device_matches(Genode::Session_policy const & policy,
Device const & dev);
void pci_device_specific_info(Device const & dev,