Arm: Initialize interrupts and scheduling.

This commit is contained in:
Udo Steinberg 2019-06-20 15:23:00 -04:00
parent e99acab841
commit d82273ba52
3 changed files with 71 additions and 12 deletions

View File

@ -20,14 +20,16 @@
#include "bitmap.hpp" #include "bitmap.hpp"
#include "event.hpp" #include "event.hpp"
#include "intid.hpp" #include "intid.hpp"
#include "sm.hpp"
#include "smmu.hpp" #include "smmu.hpp"
#include "status.hpp"
class Sm;
class Interrupt final : private Intid class Interrupt final : private Intid
{ {
private: private:
static inline constinit Refptr<Sm> table_s[NUM_SPI];
static inline constinit Refptr<Sm> table_e[NUM_ESPI];
static inline constinit Refptr<Sm> table_l[NUM_LPI];
static inline constinit Bitmap<NUM_SPI> guest_s; static inline constinit Bitmap<NUM_SPI> guest_s;
static inline constinit Bitmap<NUM_ESPI> guest_e; static inline constinit Bitmap<NUM_ESPI> guest_e;
@ -56,14 +58,28 @@ class Interrupt final : private Intid
RKE, RKE,
}; };
static void *get_ptr (arm_intid_t iid) static Refptr<Sm> *get_ptr (arm_intid_t iid)
{ {
// No interrupt semaphores for SMMU IIDs // No interrupt semaphores for SMMU IIDs
if (Smmu::using_iid (iid)) [[unlikely]] if (Smmu::using_iid (iid)) [[unlikely]]
return nullptr; return nullptr;
unsigned n;
switch (Intid::type (iid)) { switch (Intid::type (iid)) {
case Intid::Type::SPI:
n = Intid::to_spi (iid);
return n < num_spi ? table_s + n : nullptr;
case Intid::Type::ESPI:
n = Intid::to_espi (iid);
return n < num_espi ? table_e + n : nullptr;
case Intid::Type::LPI:
n = Intid::to_lpi (iid);
return n < num_lpi ? table_l + n : nullptr;
default: default:
return nullptr; return nullptr;
} }

View File

@ -15,8 +15,10 @@
* GNU General Public License version 2 for more details. * GNU General Public License version 2 for more details.
*/ */
#include "acpi.hpp"
#include "compiler.hpp" #include "compiler.hpp"
#include "cpu.hpp" #include "cpu.hpp"
#include "ec.hpp"
#include "gits.hpp" #include "gits.hpp"
#include "smmu.hpp" #include "smmu.hpp"
@ -38,8 +40,16 @@ extern "C" [[noreturn]] void bootstrap (cpu_t c, unsigned e)
panic ("SMMU initialization failed"); panic ("SMMU initialization failed");
} }
// Idle EC must exist before scheduler invocation
if (!Acpi::resume)
Ec::create_idle();
// Barrier: wait for all CPUs to arrive here // Barrier: wait for all CPUs to arrive here
for (Cpu::online++; Cpu::online != Cpu::count; pause()) ; for (Cpu::online++; Cpu::online != Cpu::count; pause()) ;
for (;;) ; if (!Acpi::resume)
if (Cpu::bsp)
Ec::create_root();
Scheduler::schedule();
} }

View File

@ -21,10 +21,8 @@
#include "gicc.hpp" #include "gicc.hpp"
#include "gicd.hpp" #include "gicd.hpp"
#include "gicr.hpp" #include "gicr.hpp"
#include "hazard.hpp"
#include "interrupt.hpp" #include "interrupt.hpp"
#include "stdio.hpp" #include "stdio.hpp"
#include "timeout.hpp"
void Interrupt::rke_handler() void Interrupt::rke_handler()
{ {
@ -39,7 +37,7 @@ Event::Selector Interrupt::handle_sgi (unsigned n, auto const &dir)
Counter::req[n].inc(); Counter::req[n].inc();
switch (n) { switch (n) {
case Request::RRQ: break; case Request::RRQ: Scheduler::requeue(); break;
case Request::RKE: rke_handler(); break; case Request::RKE: rke_handler(); break;
} }
@ -69,7 +67,13 @@ Event::Selector Interrupt::handle_spi (unsigned n, auto const &dir)
{ {
assert (n < num_spi); assert (n < num_spi);
if (Smmu::using_iid (Intid::from_spi (n))) { // Atomic load because other CPUs can update the table concurrently
Sm *const sm { table_s[n].atomic_load() };
if (sm) [[likely]]
sm->up();
else if (Smmu::using_iid (Intid::from_spi (n))) {
Smmu::interrupt (Intid::from_spi (n)); Smmu::interrupt (Intid::from_spi (n));
@ -92,6 +96,12 @@ Event::Selector Interrupt::handle_espi (unsigned n, auto const &)
{ {
assert (n < num_espi); assert (n < num_espi);
// Atomic load because other CPUs can update the table concurrently
Sm *const sm { table_e[n].atomic_load() };
if (sm) [[likely]]
sm->up();
return Event::Selector::NONE; return Event::Selector::NONE;
} }
@ -99,6 +109,12 @@ Event::Selector Interrupt::handle_lpi (unsigned n)
{ {
assert (n < num_lpi); assert (n < num_lpi);
// Atomic load because other CPUs can update the table concurrently
Sm *const sm { table_l[n].atomic_load() };
if (sm) [[likely]]
sm->up();
return Event::Selector::NONE; return Event::Selector::NONE;
} }
@ -132,9 +148,9 @@ void Interrupt::tmr_act_set (bool a)
Gicr::act_set (Intid::from_ppi (Timer::ppi_el1_v), a); Gicr::act_set (Intid::from_ppi (Timer::ppi_el1_v), a);
} }
void Interrupt::deactivate (Sm *) void Interrupt::deactivate (Sm *sm)
{ {
auto const iid { 0 }; auto const iid { sm->get_iid() };
// An LPI does not require deactivation // An LPI does not require deactivation
if (Intid::type (iid) == Type::LPI) if (Intid::type (iid) == Type::LPI)
@ -151,7 +167,24 @@ void Interrupt::deactivate (Sm *)
Status Interrupt::assign (Sm *sm, cpu_t cpu, uint16_t idx, pci_t src, uint8_t cfg, uintptr_t &msi_addr, uintptr_t &msi_data) Status Interrupt::assign (Sm *sm, cpu_t cpu, uint16_t idx, pci_t src, uint8_t cfg, uintptr_t &msi_addr, uintptr_t &msi_data)
{ {
// Determine interrupt ID // Determine interrupt ID
auto const iid { idx }; auto const iid { sm ? sm->get_iid() : idx };
// Obtain interrupt semaphore table pointer
auto const ptr { get_ptr (iid) };
// Pointer must be valid
if (!ptr) [[unlikely]]
return Status::BAD_PAR;
{ Refptr<Sm> ref { sm };
// Failed to acquire reference
if (ref != sm) [[unlikely]]
return Status::ABORTED;
// Atomically replace Refptr<Sm> in the interrupt semaphore table
ptr->atomic_swap (ref);
}
// Detach // Detach
if (!sm) [[unlikely]] if (!sm) [[unlikely]]