Skip to content
Snippets Groups Projects
Commit 5fc9daf8 authored by Asias He's avatar Asias He
Browse files

interrupt: Support interrupt sharing


This patch makes multiple devices which share the same interrupt line
works, e.g. on GCE, it shares virito-net and virtio-scsi interrupts.

Signed-off-by: default avatarAsias He <asias@cloudius-systems.com>
parent 75e25751
No related branches found
No related tags found
No related merge requests found
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
#include <libc/signal.hh> #include <libc/signal.hh>
#include <apic.hh> #include <apic.hh>
#include <osv/prio.hh> #include <osv/prio.hh>
#include <osv/rcu.hh>
#include <osv/mutex.h>
typedef boost::format fmt; typedef boost::format fmt;
...@@ -100,44 +102,97 @@ interrupt_descriptor_table::load_on_cpu() ...@@ -100,44 +102,97 @@ interrupt_descriptor_table::load_on_cpu()
unsigned interrupt_descriptor_table::register_interrupt_handler( unsigned interrupt_descriptor_table::register_interrupt_handler(
std::function<bool ()> pre_eoi, std::function<bool ()> pre_eoi,
std::function<void ()> eoi, std::function<void ()> eoi,
std::function<void ()> handler) std::function<void ()> post_eoi)
{ {
for (unsigned i = 32; i < 256; ++i) { WITH_LOCK(_lock) {
if (!_handlers[i].post_eoi) { for (unsigned i = 32; i < 256; ++i) {
_handlers[i].eoi = eoi; auto o = _handlers[i].read_by_owner();
_handlers[i].pre_eoi = pre_eoi; if (o == nullptr) {
_handlers[i].post_eoi = handler; auto n = new handler(o, pre_eoi, eoi, post_eoi);
return i;
_handlers[i].assign(n);
if (o)
osv::rcu_dispose(o);
return i;
}
} }
} }
abort(); abort();
} }
unsigned interrupt_descriptor_table::register_level_triggered_handler( unsigned interrupt_descriptor_table::register_interrupt_handler(
unsigned gsi,
std::function<bool ()> pre_eoi, std::function<bool ()> pre_eoi,
std::function<void ()> handler) std::function<void ()> eoi,
std::function<void ()> post_eoi)
{ {
return register_interrupt_handler(pre_eoi, [] { apic->eoi(); }, handler); WITH_LOCK(_lock) {
for (unsigned i = 32; i < 256; ++i) {
auto o = _handlers[i].read_by_owner();
if ((o && o->gsi == gsi) || o == nullptr) {
auto n = new handler(o, pre_eoi, eoi, post_eoi);
n->gsi = gsi;
_handlers[i].assign(n);
if (o)
osv::rcu_dispose(o);
return i;
}
}
}
abort();
} }
unsigned interrupt_descriptor_table::register_handler(std::function<void ()> handler) unsigned interrupt_descriptor_table::register_level_triggered_handler(
unsigned gsi,
std::function<bool ()> pre_eoi,
std::function<void ()> post_eoi)
{ {
return register_level_triggered_handler([] {return true;}, handler); return register_interrupt_handler(gsi, pre_eoi, [] { apic->eoi(); }, post_eoi);
} }
unsigned interrupt_descriptor_table::register_handler(std::function<void ()> post_eoi)
{
return register_interrupt_handler([] { return true; }, [] { apic->eoi(); }, post_eoi);
}
void interrupt_descriptor_table::unregister_handler(unsigned vector) void interrupt_descriptor_table::unregister_handler(unsigned vector)
{ {
_handlers[vector].eoi = {}; WITH_LOCK(_lock) {
_handlers[vector].pre_eoi = {}; auto o = _handlers[vector].read_by_owner();
_handlers[vector].post_eoi = {}; _handlers[vector].assign(nullptr);
if (o)
osv::rcu_dispose(o);
}
} }
void interrupt_descriptor_table::invoke_interrupt(unsigned vector) void interrupt_descriptor_table::invoke_interrupt(unsigned vector)
{ {
_handlers[vector].pre_eoi(); WITH_LOCK(osv::rcu_read_lock) {
_handlers[vector].eoi(); unsigned i, nr_shared;
_handlers[vector].post_eoi(); bool handled = false;
auto ptr = _handlers[vector].read();
if (!ptr) {
return;
}
nr_shared = ptr->pre_eois.size();
for (i = 0 ; i < nr_shared; i++) {
handled = ptr->pre_eois[i]();
if (handled) {
break;
}
}
ptr->eoi();
if (handled) {
ptr->post_eois[i]();
}
}
} }
extern "C" { void interrupt(exception_frame* frame); } extern "C" { void interrupt(exception_frame* frame); }
......
...@@ -11,6 +11,9 @@ ...@@ -11,6 +11,9 @@
#include <stdint.h> #include <stdint.h>
#include <functional> #include <functional>
#include <osv/types.h> #include <osv/types.h>
#include <osv/rcu.hh>
#include <osv/mutex.h>
#include <vector>
struct exception_frame { struct exception_frame {
ulong r15; ulong r15;
...@@ -43,8 +46,9 @@ public: ...@@ -43,8 +46,9 @@ public:
interrupt_descriptor_table(); interrupt_descriptor_table();
void load_on_cpu(); void load_on_cpu();
unsigned register_handler(std::function<void ()> handler); unsigned register_handler(std::function<void ()> handler);
//The pre_eoi should 'true' when the interrupt is for the device, 'false' otherwise. // The pre_eoi should 'true' when the interrupt is for the device, 'false' otherwise.
unsigned register_level_triggered_handler(std::function<bool ()> pre_eoi, std::function<void ()> handler); unsigned register_level_triggered_handler(unsigned gsi, std::function<bool ()> pre_eoi, std::function<void ()> handler);
unsigned register_interrupt_handler(unsigned gsi, std::function<bool ()> pre_eoi, std::function<void ()> eoi, std::function<void ()> handler);
unsigned register_interrupt_handler(std::function<bool ()> pre_eoi, std::function<void ()> eoi, std::function<void ()> handler); unsigned register_interrupt_handler(std::function<bool ()> pre_eoi, std::function<void ()> eoi, std::function<void ()> handler);
void unregister_handler(unsigned vector); void unregister_handler(unsigned vector);
void invoke_interrupt(unsigned vector); void invoke_interrupt(unsigned vector);
...@@ -71,11 +75,25 @@ private: ...@@ -71,11 +75,25 @@ private:
void add_entry(unsigned vec, unsigned ist, void (*handler)()); void add_entry(unsigned vec, unsigned ist, void (*handler)());
idt_entry _idt[256]; idt_entry _idt[256];
struct handler { struct handler {
handler(handler *h,
std::function<bool ()> _pre_eoi,
std::function<void ()> _eoi,
std::function<void ()> _post_eoi)
{
if (h) {
*this = *h;
}
eoi = _eoi;
pre_eois.push_back(_pre_eoi);
post_eois.push_back(_post_eoi);
}
std::vector<std::function<bool ()>> pre_eois;
std::function<void ()> eoi; std::function<void ()> eoi;
std::function<bool ()> pre_eoi; std::vector<std::function<void ()>> post_eois;
std::function<void ()> post_eoi; unsigned gsi;
}; };
handler _handlers[256]; osv::rcu_ptr<handler> _handlers[256];
mutex _lock;
}; };
extern interrupt_descriptor_table idt; extern interrupt_descriptor_table idt;
......
...@@ -82,9 +82,8 @@ gsi_edge_interrupt::~gsi_edge_interrupt() ...@@ -82,9 +82,8 @@ gsi_edge_interrupt::~gsi_edge_interrupt()
gsi_level_interrupt::gsi_level_interrupt(unsigned gsi, gsi_level_interrupt::gsi_level_interrupt(unsigned gsi,
std::function<bool ()> ack, std::function<bool ()> ack,
std::function<void ()> handler) std::function<void ()> handler)
: _vector(idt.register_level_triggered_handler(ack, handler)) : _vector(idt.register_level_triggered_handler(gsi, ack, handler))
{ {
//TODO: Interrupt sharing support
_gsi.set(gsi, _vector); _gsi.set(gsi, _vector);
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment