2020-05-25 08:59:09 +00:00
|
|
|
// Copyright 2020, ARM Limited.
|
|
|
|
//
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
|
|
|
|
|
|
|
use super::interrupt_controller::{Error, InterruptController};
|
2021-03-23 11:41:36 +00:00
|
|
|
extern crate arch;
|
2021-06-01 12:03:05 +00:00
|
|
|
use arch::aarch64::gic::GicDevice;
|
2020-05-25 08:59:09 +00:00
|
|
|
use std::result;
|
2021-06-01 12:03:05 +00:00
|
|
|
use std::sync::{Arc, Mutex};
|
2020-05-25 08:59:09 +00:00
|
|
|
use vm_device::interrupt::{
|
2021-03-14 06:35:43 +00:00
|
|
|
InterruptIndex, InterruptManager, InterruptSourceConfig, InterruptSourceGroup,
|
|
|
|
LegacyIrqSourceConfig, MsiIrqGroupConfig,
|
2020-05-25 08:59:09 +00:00
|
|
|
};
|
2021-02-09 07:28:24 +00:00
|
|
|
use vmm_sys_util::eventfd::EventFd;
|
2020-05-25 08:59:09 +00:00
|
|
|
|
|
|
|
type Result<T> = result::Result<T, Error>;
|
|
|
|
|
2021-03-14 06:35:43 +00:00
|
|
|
// Reserve 32 IRQs for legacy device.
|
2021-03-23 11:41:36 +00:00
|
|
|
pub const IRQ_LEGACY_BASE: usize = arch::layout::IRQ_BASE as usize;
|
2020-05-25 08:59:09 +00:00
|
|
|
pub const IRQ_LEGACY_COUNT: usize = 32;
|
|
|
|
|
|
|
|
// This Gic struct implements InterruptController to provide interrupt delivery service.
|
|
|
|
// The Gic source files in arch/ folder maintain the Aarch64 specific Gic device.
|
|
|
|
// The 2 Gic instances could be merged together.
|
|
|
|
// Leave this refactoring to future. Two options may be considered:
|
|
|
|
// 1. Move Gic*.rs from arch/ folder here.
|
|
|
|
// 2. Move this file and ioapic.rs to arch/, as they are architecture specific.
|
|
|
|
pub struct Gic {
|
|
|
|
interrupt_source_group: Arc<Box<dyn InterruptSourceGroup>>,
|
2021-06-01 12:03:05 +00:00
|
|
|
gic_device: Option<Arc<Mutex<Box<dyn GicDevice>>>>,
|
2020-05-25 08:59:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Gic {
|
|
|
|
pub fn new(
|
|
|
|
_vcpu_count: u8,
|
|
|
|
interrupt_manager: Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
|
|
|
|
) -> Result<Gic> {
|
|
|
|
let interrupt_source_group = interrupt_manager
|
|
|
|
.create_group(MsiIrqGroupConfig {
|
2021-03-14 06:35:43 +00:00
|
|
|
base: IRQ_LEGACY_BASE as InterruptIndex,
|
2020-05-25 08:59:09 +00:00
|
|
|
count: IRQ_LEGACY_COUNT as InterruptIndex,
|
|
|
|
})
|
|
|
|
.map_err(Error::CreateInterruptSourceGroup)?;
|
|
|
|
|
|
|
|
Ok(Gic {
|
|
|
|
interrupt_source_group,
|
2021-06-01 12:03:05 +00:00
|
|
|
gic_device: None,
|
2020-05-25 08:59:09 +00:00
|
|
|
})
|
|
|
|
}
|
2021-06-01 12:03:05 +00:00
|
|
|
|
|
|
|
pub fn set_gic_device(&mut self, gic_device: Arc<Mutex<Box<dyn GicDevice>>>) {
|
|
|
|
self.gic_device = Some(gic_device);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_gic_device(&self) -> Option<&Arc<Mutex<Box<dyn GicDevice>>>> {
|
|
|
|
self.gic_device.as_ref()
|
|
|
|
}
|
2020-05-25 08:59:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl InterruptController for Gic {
|
|
|
|
fn enable(&self) -> Result<()> {
|
2021-03-14 06:35:43 +00:00
|
|
|
// Set irqfd for legacy interrupts
|
2020-08-23 07:45:44 +00:00
|
|
|
self.interrupt_source_group
|
2020-05-25 08:59:09 +00:00
|
|
|
.enable()
|
|
|
|
.map_err(Error::EnableInterrupt)?;
|
2021-03-14 06:35:43 +00:00
|
|
|
|
|
|
|
// Set irq_routing for legacy interrupts.
|
|
|
|
// irqchip: Hardcode to 0 as we support only 1 GIC
|
|
|
|
// pin: Use irq number as pin
|
|
|
|
for i in IRQ_LEGACY_BASE..(IRQ_LEGACY_BASE + IRQ_LEGACY_COUNT) {
|
|
|
|
let config = LegacyIrqSourceConfig {
|
|
|
|
irqchip: 0,
|
2021-03-23 11:41:36 +00:00
|
|
|
pin: (i - IRQ_LEGACY_BASE) as u32,
|
2021-03-14 06:35:43 +00:00
|
|
|
};
|
|
|
|
self.interrupt_source_group
|
|
|
|
.update(
|
|
|
|
i as InterruptIndex,
|
|
|
|
InterruptSourceConfig::LegacyIrq(config),
|
|
|
|
)
|
|
|
|
.map_err(Error::EnableInterrupt)?;
|
|
|
|
}
|
2020-05-25 08:59:09 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
// This should be called anytime an interrupt needs to be injected into the
|
|
|
|
// running guest.
|
|
|
|
fn service_irq(&mut self, irq: usize) -> Result<()> {
|
|
|
|
self.interrupt_source_group
|
|
|
|
.trigger(irq as InterruptIndex)
|
|
|
|
.map_err(Error::TriggerInterrupt)?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2021-02-09 07:28:24 +00:00
|
|
|
|
|
|
|
fn notifier(&self, irq: usize) -> Option<EventFd> {
|
|
|
|
self.interrupt_source_group.notifier(irq as InterruptIndex)
|
|
|
|
}
|
2020-05-25 08:59:09 +00:00
|
|
|
}
|