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 "event.hpp"
#include "intid.hpp"
#include "sm.hpp"
#include "smmu.hpp"
#include "status.hpp"
class Sm;
class Interrupt final : private Intid
{
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_ESPI> guest_e;
@ -56,14 +58,28 @@ class Interrupt final : private Intid
RKE,
};
static void *get_ptr (arm_intid_t iid)
static Refptr<Sm> *get_ptr (arm_intid_t iid)
{
// No interrupt semaphores for SMMU IIDs
if (Smmu::using_iid (iid)) [[unlikely]]
return nullptr;
unsigned n;
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:
return nullptr;
}

View File

@ -15,8 +15,10 @@
* GNU General Public License version 2 for more details.
*/
#include "acpi.hpp"
#include "compiler.hpp"
#include "cpu.hpp"
#include "ec.hpp"
#include "gits.hpp"
#include "smmu.hpp"
@ -38,8 +40,16 @@ extern "C" [[noreturn]] void bootstrap (cpu_t c, unsigned e)
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
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 "gicd.hpp"
#include "gicr.hpp"
#include "hazard.hpp"
#include "interrupt.hpp"
#include "stdio.hpp"
#include "timeout.hpp"
void Interrupt::rke_handler()
{
@ -39,7 +37,7 @@ Event::Selector Interrupt::handle_sgi (unsigned n, auto const &dir)
Counter::req[n].inc();
switch (n) {
case Request::RRQ: break;
case Request::RRQ: Scheduler::requeue(); 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);
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));
@ -92,6 +96,12 @@ Event::Selector Interrupt::handle_espi (unsigned n, auto const &)
{
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;
}
@ -99,6 +109,12 @@ Event::Selector Interrupt::handle_lpi (unsigned n)
{
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;
}
@ -132,9 +148,9 @@ void Interrupt::tmr_act_set (bool 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
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)
{
// 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
if (!sm) [[unlikely]]