ACPI/IRQ: Add interrupt mode to IRQ connection

Read flags (polarity/trigger) from MADT and add information to 'Irq_connection'
arguments.

Issue #390
This commit is contained in:
Sebastian Sumpf 2012-10-05 14:23:59 +02:00 committed by Norman Feske
parent 4a1b545770
commit ff0c7825e4
5 changed files with 63 additions and 14 deletions

View File

@ -24,13 +24,17 @@ namespace Genode {
/**
* Constructor
*
* \param irq physical interrupt number
* \param irq physical interrupt number
* \param trigger interrupt trigger (e.g., level/edge)
* \param polarity interrupt trigger polarity (e.g., low/high)
*/
Irq_connection(unsigned irq)
Irq_connection(unsigned irq,
Irq_session::Trigger trigger = Irq_session::TRIGGER_UNCHANGED,
Irq_session::Polarity polarity = Irq_session::POLARITY_UNCHANGED)
:
Connection<Irq_session>(
session("ram_quota=4K, irq_number=%u", irq)),
session("ram_quota=4K, irq_number=%u, irq_trigger=%u, irq_polarity=%u",
irq, trigger, polarity)),
Irq_session_client(cap())
{ }
};

View File

@ -28,6 +28,17 @@ namespace Genode {
struct Irq_session : Session
{
/**
* Interrupt trigger
*/
enum Trigger { TRIGGER_UNCHANGED = 0, TRIGGER_LEVEL, TRIGGER_EDGE };
/**
* Interrupt trigger polarity
*/
enum Polarity { POLARITY_UNCHANGED = 0, POLARITY_HIGH, POLARITY_LOW };
static const char *service_name() { return "IRQ"; }
virtual ~Irq_session() { }

View File

@ -95,6 +95,7 @@ class Irq_override : public List<Irq_override>::Element
bool match(uint32_t irq) const { return irq == _irq; }
uint32_t gsi() const { return _gsi; }
uint32_t flags() const { return _flags; }
};
@ -196,8 +197,7 @@ class Table_wrapper
Apic_override *o = static_cast<Apic_override *>(apic);
if (verbose)
PDBG("Found IRQ %u -> GSI %u", o->irq, o->gsi);
PINF("MADT IRQ %u -> GSI %u flags: %x", o->irq, o->gsi, o->flags);
Irq_override::list()->insert(new (env()->heap()) Irq_override(o->irq, o->gsi, o->flags));
}
@ -944,7 +944,6 @@ class Acpi_table
}
if (table.is_madt()) {
if (verbose)
PDBG("Found MADT");
table.parse_madt();
@ -1127,7 +1126,7 @@ void Acpi::rewrite_irq(Pci::Session_capability &session)
if (Element::supported_acpi_format())
PINF("ACPI table format is supported by this driver");
else {
PERR("ACPI table format not supported (is too old) by this driver");
PWRN("ACPI table format not supported will not rewrite GSIs");
return;
}
@ -1161,11 +1160,14 @@ void Acpi::rewrite_irq(Pci::Session_capability &session)
/**
* Search override structures
*/
unsigned Acpi::override(unsigned irq)
unsigned Acpi::override(unsigned irq, unsigned *mode)
{
for (Irq_override *i = Irq_override::list()->first(); i; i = i->next())
if (i->match(irq))
if (i->match(irq)) {
*mode = i->flags();
return i->gsi();
}
*mode = 0;
return irq;
}

View File

@ -29,7 +29,7 @@ class Acpi
/**
* Return override GSI for IRQ
*/
static unsigned override(unsigned irq);
static unsigned override(unsigned irq, unsigned *mode);
};
#endif /* _ACPI_H_ */

View File

@ -38,6 +38,37 @@ namespace Irq {
*/
class Root : public Irq_session
{
private:
Genode::Irq_session::Trigger _mode2trigger(unsigned mode)
{
enum { EDGE = 0x4, LEVEL = 0xc };
switch (mode & 0xc) {
case EDGE:
return Genode::Irq_session::TRIGGER_EDGE;
case LEVEL:
return Genode::Irq_session::TRIGGER_LEVEL;
default:
return Genode::Irq_session::TRIGGER_UNCHANGED;
}
}
Genode::Irq_session::Polarity _mode2polarity(unsigned mode)
{
using namespace Genode;
enum { HIGH = 0x1, LOW = 0x3 };
switch (mode & 0x3) {
case HIGH:
return Genode::Irq_session::POLARITY_HIGH;
case LOW:
return Genode::Irq_session::POLARITY_LOW;
default:
return Genode::Irq_session::POLARITY_UNCHANGED;
}
}
public:
/**
@ -52,11 +83,12 @@ namespace Irq {
long irq_number = Arg_string::find_arg(args.string(), "irq_number").long_value(-1);
/* check for 'MADT' overrides */
irq_number = Acpi::override(irq_number);
unsigned mode;
irq_number = Acpi::override(irq_number, &mode);
/* allocate IRQ at parent*/
try {
Irq_connection irq(irq_number);
Irq_connection irq(irq_number, _mode2trigger(mode), _mode2polarity(mode));
irq.on_destruction(Irq_connection::KEEP_OPEN);
return irq.cap();
} catch (...) { throw Root::Unavailable(); }