pci/dt: rework pci interrupts, add gicv2m and dt msi controllers
This commit is contained in:
parent
01dbac2132
commit
7348232aa9
@ -30,8 +30,11 @@ ygg_driver_net_core = { path = "driver/net/core" }
|
||||
ygg_driver_net_loopback = { path = "driver/net/loopback" }
|
||||
ygg_driver_virtio_net = { path = "driver/virtio/net", features = ["pci"] }
|
||||
ygg_driver_virtio_gpu = { path = "driver/virtio/gpu", features = ["pci"] }
|
||||
ygg_driver_nvme = { path = "driver/block/nvme" }
|
||||
ygg_driver_ahci = { path = "driver/block/ahci" }
|
||||
ygg_driver_input = { path = "driver/input" }
|
||||
ygg_driver_usb_xhci.path = "driver/usb/xhci"
|
||||
ygg_driver_net_rtl81xx.path = "driver/net/rtl81xx"
|
||||
|
||||
memfs = { path = "driver/fs/memfs" }
|
||||
ext2 = { path = "driver/fs/ext2" }
|
||||
@ -63,9 +66,6 @@ kernel-arch-x86_64.workspace = true
|
||||
kernel-arch-x86.workspace = true
|
||||
|
||||
ygg_driver_acpi.path = "driver/acpi"
|
||||
ygg_driver_usb_xhci.path = "driver/usb/xhci"
|
||||
ygg_driver_nvme = { path = "driver/block/nvme" }
|
||||
ygg_driver_net_rtl81xx.path = "driver/net/rtl81xx"
|
||||
|
||||
acpi.workspace = true
|
||||
|
||||
@ -89,8 +89,6 @@ kernel-arch-aarch64.workspace = true
|
||||
kernel-arch-riscv64.workspace = true
|
||||
|
||||
ygg_driver_acpi.path = "driver/acpi"
|
||||
ygg_driver_usb_xhci.path = "driver/usb/xhci"
|
||||
ygg_driver_net_rtl81xx.path = "driver/net/rtl81xx"
|
||||
|
||||
[features]
|
||||
default = ["fb_console"]
|
||||
|
@ -8,7 +8,7 @@ use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
use aarch64_cpu::registers::{DAIF, MPIDR_EL1, TPIDR_EL1};
|
||||
use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
||||
use device_api::interrupt::{LocalInterruptController, MessageInterruptController};
|
||||
use device_api::interrupt::LocalInterruptController;
|
||||
use kernel_arch_interface::{
|
||||
cpu::{CpuData, CpuImpl, IpiQueue},
|
||||
guard::IrqGuard,
|
||||
@ -123,24 +123,10 @@ impl Architecture for ArchitectureImpl {
|
||||
CPU_COUNT.load(Ordering::Acquire)
|
||||
}
|
||||
|
||||
fn message_interrupt_controller() -> Option<&'static dyn MessageInterruptController> {
|
||||
None
|
||||
}
|
||||
|
||||
fn local_interrupt_controller() -> Option<&'static dyn LocalInterruptController> {
|
||||
None
|
||||
}
|
||||
|
||||
// fn local_interrupt_controller() -> Option<&'static dyn LocalInterruptController> {
|
||||
// let local = Self::local_cpu_data()?;
|
||||
// let intc = *local.gic.try_get()?;
|
||||
// Some(intc)
|
||||
// }
|
||||
|
||||
// fn message_interrupt_controller() -> &'static dyn MessageInterruptController {
|
||||
// todo!()
|
||||
// }
|
||||
|
||||
fn cpu_available_features<S: Scheduler>(_cpu: &CpuImpl<Self, S>) -> Option<&Self::CpuFeatures> {
|
||||
None
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use cpu::{CpuData, CpuFeatureSet, CpuImpl, IpiQueue};
|
||||
use device_api::interrupt::{LocalInterruptController, MessageInterruptController};
|
||||
use device_api::interrupt::LocalInterruptController;
|
||||
use task::Scheduler;
|
||||
|
||||
extern crate alloc;
|
||||
@ -72,10 +72,6 @@ pub trait Architecture: Sized + 'static {
|
||||
None
|
||||
}
|
||||
|
||||
fn message_interrupt_controller() -> Option<&'static dyn MessageInterruptController> {
|
||||
None
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
fn cpu_available_features<S: Scheduler>(cpu: &CpuImpl<Self, S>) -> Option<&Self::CpuFeatures> {
|
||||
None
|
||||
|
@ -6,7 +6,7 @@ extern crate alloc;
|
||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
use alloc::{boxed::Box, collections::btree_map::BTreeMap, vec::Vec};
|
||||
use device_api::interrupt::{LocalInterruptController, MessageInterruptController};
|
||||
use device_api::interrupt::LocalInterruptController;
|
||||
use kernel_arch_interface::{
|
||||
cpu::{CpuData, CpuImpl, IpiQueue},
|
||||
sync::IrqSafeSpinlock,
|
||||
@ -160,10 +160,6 @@ impl Architecture for ArchitectureImpl {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn message_interrupt_controller() -> Option<&'static dyn MessageInterruptController> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn idle_task() -> extern "C" fn(usize) -> ! {
|
||||
idle_task
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ use core::{
|
||||
sync::atomic::{AtomicUsize, Ordering},
|
||||
};
|
||||
|
||||
use alloc::{boxed::Box, vec::Vec};
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
use device_api::interrupt::{LocalInterruptController, MessageInterruptController};
|
||||
use kernel_arch_interface::{
|
||||
cpu::{CpuData, CpuImpl, IpiQueue},
|
||||
@ -52,8 +52,7 @@ pub struct PerCpuData {
|
||||
// 0x10, used in assembly
|
||||
pub tmp_address: usize,
|
||||
|
||||
pub local_apic: Box<dyn LocalApicInterface>,
|
||||
// pub local_apic: &'static dyn LocalApicInterface,
|
||||
pub local_apic: Arc<dyn LocalApicInterface>,
|
||||
pub available_features: CpuFeatures,
|
||||
pub enabled_features: CpuFeatures,
|
||||
}
|
||||
@ -189,11 +188,6 @@ impl Architecture for ArchitectureImpl {
|
||||
Some(cpu.local_apic.as_ref())
|
||||
}
|
||||
|
||||
fn message_interrupt_controller() -> Option<&'static dyn MessageInterruptController> {
|
||||
let cpu = Self::local_cpu_data()?;
|
||||
Some(cpu.local_apic.as_ref())
|
||||
}
|
||||
|
||||
fn cpu_enabled_features<S: Scheduler>(cpu: &CpuImpl<Self, S>) -> Option<&Self::CpuFeatures> {
|
||||
Some(&cpu.enabled_features)
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use acpi_system::AcpiSystemError;
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
device::Device,
|
||||
interrupt::{InterruptHandler, Irq},
|
||||
interrupt::{InterruptHandler, Irq, IrqVector},
|
||||
};
|
||||
use kernel_arch_x86::{intrinsics, ISA_IRQ_OFFSET};
|
||||
use libk::device::external_interrupt_controller;
|
||||
@ -157,7 +157,7 @@ impl rsdp::handler::AcpiHandler for AcpiHandlerImpl {
|
||||
}
|
||||
|
||||
impl InterruptHandler for SciHandler {
|
||||
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
|
||||
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
|
||||
log::trace!("ACPI SCI received");
|
||||
ACPI_SYSTEM.get().lock().handle_sci();
|
||||
true
|
||||
|
@ -9,7 +9,7 @@ use bytemuck::Zeroable;
|
||||
use data::ReceivedFis;
|
||||
use device_api::{
|
||||
device::Device,
|
||||
interrupt::{InterruptAffinity, InterruptHandler},
|
||||
interrupt::{InterruptAffinity, InterruptHandler, IrqVector},
|
||||
};
|
||||
use error::AhciError;
|
||||
use libk::{device::manager::probe_partitions, fs::devfs, task::runtime};
|
||||
@ -159,7 +159,7 @@ impl AhciController {
|
||||
}
|
||||
|
||||
impl InterruptHandler for AhciController {
|
||||
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
|
||||
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
|
||||
let regs = self.regs.lock();
|
||||
|
||||
let is = regs.IS.get();
|
||||
|
@ -5,6 +5,7 @@ use super::queue::CommandError;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum NvmeError {
|
||||
InitError(Error),
|
||||
InvalidBuffer(PhysicalAddress, usize),
|
||||
RequestTooLarge(usize),
|
||||
MemoryError(Error),
|
||||
@ -20,6 +21,7 @@ impl From<CommandError> for NvmeError {
|
||||
impl From<NvmeError> for Error {
|
||||
fn from(value: NvmeError) -> Self {
|
||||
match value {
|
||||
NvmeError::InitError(error) => error,
|
||||
NvmeError::RequestTooLarge(_) => Error::InvalidArgument,
|
||||
NvmeError::InvalidBuffer(_, _) => Error::InvalidArgument,
|
||||
NvmeError::MemoryError(err) => err,
|
||||
|
@ -16,7 +16,7 @@ use alloc::{collections::BTreeMap, format, sync::Arc, vec::Vec};
|
||||
use command::{IdentifyActiveNamespaceIdListRequest, IdentifyControllerRequest};
|
||||
use device_api::{
|
||||
device::Device,
|
||||
interrupt::{InterruptAffinity, InterruptHandler},
|
||||
interrupt::{InterruptAffinity, InterruptHandler, IrqVector},
|
||||
};
|
||||
use drive::NvmeNamespace;
|
||||
use libk::{
|
||||
@ -222,7 +222,7 @@ impl NvmeController {
|
||||
let range = self
|
||||
.pci
|
||||
.map_interrupt_multiple(0..io_queue_count + 1, InterruptAffinity::Any, self.clone())
|
||||
.unwrap();
|
||||
.map_err(NvmeError::InitError)?;
|
||||
|
||||
// TODO handle different MSI range allocations
|
||||
for (i, msi) in range.iter().enumerate() {
|
||||
@ -327,8 +327,10 @@ impl NvmeController {
|
||||
}
|
||||
|
||||
impl InterruptHandler for NvmeController {
|
||||
fn handle_irq(self: Arc<Self>, vector: Option<usize>) -> bool {
|
||||
let vector = vector.expect("Only MSI-X interrupts are supported");
|
||||
fn handle_irq(self: Arc<Self>, vector: IrqVector) -> bool {
|
||||
let IrqVector::Msi(vector) = vector else {
|
||||
unreachable!("Only MSI-x interrupts are supported for NVMe");
|
||||
};
|
||||
|
||||
if vector == 0 {
|
||||
self.admin_q.get().process_completions() != 0
|
||||
|
@ -489,11 +489,11 @@ impl MsiXVectorTable<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_range<C: MessageInterruptController + ?Sized>(
|
||||
pub fn register_range(
|
||||
&mut self,
|
||||
start: usize,
|
||||
end: usize,
|
||||
ic: &C,
|
||||
ic: &Arc<dyn MessageInterruptController>,
|
||||
affinity: InterruptAffinity,
|
||||
handler: Arc<dyn InterruptHandler>,
|
||||
) -> Result<Vec<MsiInfo>, Error> {
|
||||
@ -505,7 +505,7 @@ impl MsiXVectorTable<'_> {
|
||||
};
|
||||
end - start
|
||||
];
|
||||
ic.register_msi_range(&mut range, handler)?;
|
||||
ic.clone().register_msi_range(&mut range, handler)?;
|
||||
|
||||
for (i, info) in range.iter().enumerate() {
|
||||
let index = i + start;
|
||||
@ -519,13 +519,13 @@ impl MsiXVectorTable<'_> {
|
||||
}
|
||||
|
||||
impl<'s, S: PciConfigurationSpace + ?Sized + 's> MsiData<'s, S> {
|
||||
pub fn register<C: MessageInterruptController + ?Sized>(
|
||||
pub fn register(
|
||||
&mut self,
|
||||
ic: &C,
|
||||
ic: &Arc<dyn MessageInterruptController>,
|
||||
affinity: InterruptAffinity,
|
||||
handler: Arc<dyn InterruptHandler>,
|
||||
) -> Result<MsiInfo, Error> {
|
||||
let info = ic.register_msi(affinity, handler)?;
|
||||
let info = ic.clone().register_msi(affinity, handler)?;
|
||||
|
||||
let mut w0 = self.space.read_u16(self.offset + 2);
|
||||
// Enable the vector first
|
||||
|
@ -3,9 +3,12 @@ use core::ops::Range;
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
use device_api::{
|
||||
device::Device,
|
||||
interrupt::{InterruptAffinity, InterruptHandler, IrqOptions, MsiInfo},
|
||||
interrupt::{
|
||||
ExternalInterruptController, InterruptAffinity, InterruptHandler, Irq, IrqOptions,
|
||||
MessageInterruptController, MsiInfo,
|
||||
},
|
||||
};
|
||||
use libk::device::{message_interrupt_controller, register_global_interrupt};
|
||||
use libk::device::external_interrupt_controller;
|
||||
use libk_util::{sync::spin_rwlock::IrqSafeRwLock, OneTimeInit};
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
@ -58,11 +61,14 @@ pub enum PreferredInterruptMode {
|
||||
}
|
||||
|
||||
enum ConfiguredInterruptMode {
|
||||
MsiX(MsiXVectorTable<'static>),
|
||||
Msi,
|
||||
LegacyPin(PciInterruptPin),
|
||||
MsiX(
|
||||
Arc<dyn MessageInterruptController>,
|
||||
MsiXVectorTable<'static>,
|
||||
),
|
||||
Msi(Arc<dyn MessageInterruptController>),
|
||||
LegacyPin(Arc<dyn ExternalInterruptController>, PciInterruptPin),
|
||||
#[cfg_attr(not(target_arch = "x86"), allow(unused))]
|
||||
LegacyLine(u8),
|
||||
LegacyLine(Arc<dyn ExternalInterruptController>, u8),
|
||||
None,
|
||||
}
|
||||
|
||||
@ -78,6 +84,12 @@ pub struct PciInterruptRoute {
|
||||
pub options: IrqOptions,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PciMsiRoute {
|
||||
// TODO `msi-base`
|
||||
pub controller: Arc<dyn MessageInterruptController>,
|
||||
}
|
||||
|
||||
/// Used to store PCI bus devices which were enumerated by the kernel
|
||||
pub struct PciBusDevice {
|
||||
pub(crate) info: PciDeviceInfo,
|
||||
@ -123,10 +135,10 @@ impl PciDeviceInfo {
|
||||
pub fn init_interrupts(&self, preferred_mode: PreferredInterruptMode) -> Result<(), Error> {
|
||||
self.interrupt_config
|
||||
.try_init_with(|| {
|
||||
let configured_mode = if self.segment.has_msi
|
||||
&& let PreferredInterruptMode::Msi(want_msix) = preferred_mode
|
||||
let configured_mode = if let PreferredInterruptMode::Msi(want_msix) = preferred_mode
|
||||
&& let Some(msi_route) = self.segment.msi_translation_map.map_msi(self.address)
|
||||
{
|
||||
// Try MSI-X first
|
||||
// Try to setup MSI (or MSI-x, if requested)
|
||||
let mut result = None;
|
||||
if want_msix
|
||||
&& let Some(mut msix) = self.config_space.capability::<MsiXCapability>()
|
||||
@ -137,46 +149,55 @@ impl PciDeviceInfo {
|
||||
msix.set_function_mask(false);
|
||||
msix.set_enabled(true);
|
||||
|
||||
result = Some(ConfiguredInterruptMode::MsiX(vt));
|
||||
result = Some(ConfiguredInterruptMode::MsiX(
|
||||
msi_route.controller.clone(),
|
||||
vt,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Then try MSI
|
||||
// Fall back to MSI if MSI-x is not available or not requested
|
||||
if result.is_none() && self.config_space.capability::<MsiCapability>().is_some()
|
||||
{
|
||||
result = Some(ConfiguredInterruptMode::Msi)
|
||||
result = Some(ConfiguredInterruptMode::Msi(msi_route.controller));
|
||||
}
|
||||
|
||||
// And then fall back to legacy
|
||||
// Fall back to legacy IRQ if nothing else works
|
||||
if let Some(result) = result {
|
||||
result
|
||||
} else {
|
||||
self.legacy_interrupt_mode()
|
||||
}
|
||||
} else {
|
||||
// Ignore preferred_mode, the only supported is Legacy
|
||||
// MSI not requested or segment does not have MSI functionality
|
||||
self.legacy_interrupt_mode()
|
||||
};
|
||||
|
||||
IrqSafeRwLock::new(InterruptConfig {
|
||||
preferred_mode,
|
||||
configured_mode,
|
||||
})
|
||||
})
|
||||
.expect("Attempted to double-configure interrupts for a PCI device");
|
||||
.expect("Possible bug: double-initialization of PCI(e) interrupt config");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn legacy_interrupt_mode(&self) -> ConfiguredInterruptMode {
|
||||
let Ok(intc) = external_interrupt_controller() else {
|
||||
return ConfiguredInterruptMode::None;
|
||||
};
|
||||
|
||||
// TODO this should be retrieved from interrupt map
|
||||
#[cfg(any(target_arch = "x86", rust_analyzer))]
|
||||
{
|
||||
if let Some(irq) = self.config_space.interrupt_line() {
|
||||
return ConfiguredInterruptMode::LegacyLine(irq);
|
||||
return ConfiguredInterruptMode::LegacyLine(intc.clone(), irq);
|
||||
}
|
||||
}
|
||||
|
||||
match self.config_space.interrupt_pin() {
|
||||
Some(pin) => ConfiguredInterruptMode::LegacyPin(pin),
|
||||
Some(pin) => ConfiguredInterruptMode::LegacyPin(intc.clone(), pin),
|
||||
None => ConfiguredInterruptMode::None,
|
||||
}
|
||||
}
|
||||
@ -189,27 +210,26 @@ impl PciDeviceInfo {
|
||||
let mut irq = self.interrupt_config.get().write();
|
||||
|
||||
match &mut irq.configured_mode {
|
||||
ConfiguredInterruptMode::MsiX(msix) => {
|
||||
let info =
|
||||
msix.register_range(0, 1, message_interrupt_controller()?, affinity, handler)?;
|
||||
Ok(Some(info[0]))
|
||||
}
|
||||
ConfiguredInterruptMode::Msi => {
|
||||
ConfiguredInterruptMode::Msi(controller) => {
|
||||
let mut msi = self
|
||||
.config_space
|
||||
.capability::<MsiCapability>()
|
||||
.ok_or(Error::InvalidOperation)?;
|
||||
|
||||
let info = msi.register(message_interrupt_controller()?, affinity, handler)?;
|
||||
let info = msi.register(controller, affinity, handler)?;
|
||||
|
||||
Ok(Some(info))
|
||||
}
|
||||
ConfiguredInterruptMode::LegacyPin(pin) => {
|
||||
self.try_map_legacy(*pin, handler)?;
|
||||
ConfiguredInterruptMode::MsiX(controller, msix) => {
|
||||
let info = msix.register_range(0, 1, controller, affinity, handler)?;
|
||||
Ok(Some(info[0]))
|
||||
}
|
||||
ConfiguredInterruptMode::LegacyPin(intc, pin) => {
|
||||
self.try_map_legacy(intc.as_ref(), *pin, handler)?;
|
||||
Ok(None)
|
||||
}
|
||||
ConfiguredInterruptMode::LegacyLine(irq) => {
|
||||
self.try_map_legacy_line(*irq, handler)?;
|
||||
ConfiguredInterruptMode::LegacyLine(intc, irq) => {
|
||||
self.try_map_legacy_line(intc.as_ref(), *irq, handler)?;
|
||||
Ok(None)
|
||||
}
|
||||
ConfiguredInterruptMode::None => Err(Error::InvalidOperation),
|
||||
@ -227,19 +247,16 @@ impl PciDeviceInfo {
|
||||
let end = vector_range.end;
|
||||
|
||||
match &mut irq.configured_mode {
|
||||
ConfiguredInterruptMode::MsiX(msix) => msix.register_range(
|
||||
start,
|
||||
end,
|
||||
message_interrupt_controller()?,
|
||||
affinity,
|
||||
handler,
|
||||
),
|
||||
ConfiguredInterruptMode::MsiX(controller, msix) => {
|
||||
msix.register_range(start, end, controller, affinity, handler)
|
||||
}
|
||||
_ => Err(Error::InvalidOperation),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_map_legacy(
|
||||
&self,
|
||||
intc: &dyn ExternalInterruptController,
|
||||
pin: PciInterruptPin,
|
||||
handler: Arc<dyn InterruptHandler>,
|
||||
) -> Result<(), Error> {
|
||||
@ -260,17 +277,22 @@ impl PciDeviceInfo {
|
||||
route.number
|
||||
);
|
||||
|
||||
register_global_interrupt(route.number, route.options, handler)
|
||||
let irq = Irq::External(route.number);
|
||||
intc.register_irq(irq, route.options, handler)?;
|
||||
intc.enable_irq(irq)
|
||||
}
|
||||
|
||||
fn try_map_legacy_line(
|
||||
&self,
|
||||
intc: &dyn ExternalInterruptController,
|
||||
line: u8,
|
||||
handler: Arc<dyn InterruptHandler>,
|
||||
) -> Result<(), Error> {
|
||||
log::debug!("PCI {} -> IRQ#{}", self.address, line);
|
||||
|
||||
register_global_interrupt(line as _, Default::default(), handler)
|
||||
let irq = Irq::External(line as u32);
|
||||
intc.register_irq(irq, Default::default(), handler)?;
|
||||
intc.enable_irq(irq)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,13 @@
|
||||
use alloc::collections::btree_map::BTreeMap;
|
||||
use core::fmt;
|
||||
|
||||
use alloc::{collections::btree_map::BTreeMap, sync::Arc, vec::Vec};
|
||||
use device_api::interrupt::MessageInterruptController;
|
||||
use libk::error::Error;
|
||||
|
||||
use crate::device::{PciInterrupt, PciInterruptRoute};
|
||||
use crate::{
|
||||
device::{PciInterrupt, PciInterruptRoute, PciMsiRoute},
|
||||
PciAddress,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PciInterruptMap {
|
||||
@ -11,6 +17,24 @@ pub enum PciInterruptMap {
|
||||
Legacy,
|
||||
}
|
||||
|
||||
// TODO device-tree also provides a "msi-base" value, which is ignored and assumed to be zero for
|
||||
// now
|
||||
pub struct PciFixedMsiMapping {
|
||||
pub start_address: PciAddress,
|
||||
pub end_address: PciAddress,
|
||||
pub controller: Arc<dyn MessageInterruptController>,
|
||||
}
|
||||
|
||||
pub struct PciFixedMsiMap {
|
||||
pub entries: Vec<PciFixedMsiMapping>,
|
||||
}
|
||||
|
||||
pub enum PciMsiMap {
|
||||
Fixed(PciFixedMsiMap),
|
||||
Identity(Arc<dyn MessageInterruptController>),
|
||||
Legacy,
|
||||
}
|
||||
|
||||
impl PciInterruptMap {
|
||||
pub fn map_interrupt(&self, interrupt: &PciInterrupt) -> Result<PciInterruptRoute, Error> {
|
||||
match self {
|
||||
@ -61,3 +85,57 @@ impl PciInterruptMap {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PciMsiMap {
|
||||
pub fn map_msi(&self, address: PciAddress) -> Option<PciMsiRoute> {
|
||||
match self {
|
||||
Self::Fixed(map) => map.map_msi(address),
|
||||
Self::Identity(controller) => Some(PciMsiRoute {
|
||||
controller: controller.clone(),
|
||||
}),
|
||||
Self::Legacy => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for PciMsiMap {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Legacy => f.debug_struct("Legacy").finish(),
|
||||
Self::Fixed(map) => f
|
||||
.debug_struct("Fixed")
|
||||
.field("entries", &map.entries)
|
||||
.finish(),
|
||||
Self::Identity(_) => f.debug_struct("Identity").finish(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PciFixedMsiMap {
|
||||
pub fn map_msi(&self, address: PciAddress) -> Option<PciMsiRoute> {
|
||||
for entry in self.entries.iter() {
|
||||
if entry.contains(address) {
|
||||
let route = PciMsiRoute {
|
||||
controller: entry.controller.clone(),
|
||||
};
|
||||
return Some(route);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl PciFixedMsiMapping {
|
||||
pub fn contains(&self, address: PciAddress) -> bool {
|
||||
self.start_address <= address && self.end_address > address
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for PciFixedMsiMapping {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("PciFixedMsiMapping")
|
||||
.field("start_address", &self.start_address)
|
||||
.field("end_address", &self.end_address)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
@ -13,13 +13,16 @@ use alloc::{format, sync::Arc, vec::Vec};
|
||||
|
||||
use bitflags::bitflags;
|
||||
use device::{PciBusDevice, PciDeviceInfo};
|
||||
use interrupt::PciInterruptMap;
|
||||
use interrupt::{PciInterruptMap, PciMsiMap};
|
||||
use libk::fs::sysfs::{self, object::KObject};
|
||||
use libk_mm::address::PhysicalAddress;
|
||||
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
|
||||
use space::legacy;
|
||||
use yggdrasil_abi::{error::Error, primitive_enum};
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use device_api::interrupt::MessageInterruptController;
|
||||
|
||||
pub mod capability;
|
||||
pub mod device;
|
||||
pub mod driver;
|
||||
@ -124,6 +127,45 @@ struct BusAddressAllocator {
|
||||
offset_32: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PciSegmentInfo {
|
||||
pub segment_number: u8,
|
||||
pub bus_number_start: u8,
|
||||
pub bus_number_end: u8,
|
||||
pub ecam_phys_base: Option<PhysicalAddress>,
|
||||
|
||||
pub irq_translation_map: PciInterruptMap,
|
||||
pub msi_translation_map: PciMsiMap,
|
||||
}
|
||||
|
||||
/// Represents a single PCIe bus segment
|
||||
pub struct PciBusSegment {
|
||||
allocator: Option<BusAddressAllocator>,
|
||||
info: Arc<PciSegmentInfo>,
|
||||
devices: Vec<Arc<KObject<IrqSafeSpinlock<PciBusDevice>>>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PciRangeType {
|
||||
Configuration,
|
||||
Io,
|
||||
Memory32,
|
||||
Memory64,
|
||||
}
|
||||
|
||||
pub struct PciAddressRange {
|
||||
pub ty: PciRangeType,
|
||||
pub bus_number: u8,
|
||||
pub pci_base: u64,
|
||||
pub host_base: PhysicalAddress,
|
||||
pub size: usize,
|
||||
}
|
||||
|
||||
/// Manager struct to store and control all PCI devices in the system
|
||||
pub struct PciBusManager {
|
||||
segments: Vec<PciBusSegment>,
|
||||
}
|
||||
|
||||
#[cfg_attr(
|
||||
any(target_arch = "x86_64", target_arch = "x86", target_arch = "riscv64"),
|
||||
allow(dead_code)
|
||||
@ -195,45 +237,6 @@ impl BusAddressAllocator {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PciSegmentInfo {
|
||||
pub segment_number: u8,
|
||||
pub bus_number_start: u8,
|
||||
pub bus_number_end: u8,
|
||||
pub ecam_phys_base: Option<PhysicalAddress>,
|
||||
|
||||
pub irq_translation_map: PciInterruptMap,
|
||||
pub has_msi: bool,
|
||||
}
|
||||
|
||||
/// Represents a single PCIe bus segment
|
||||
pub struct PciBusSegment {
|
||||
allocator: Option<BusAddressAllocator>,
|
||||
info: Arc<PciSegmentInfo>,
|
||||
devices: Vec<Arc<KObject<IrqSafeSpinlock<PciBusDevice>>>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PciRangeType {
|
||||
Configuration,
|
||||
Io,
|
||||
Memory32,
|
||||
Memory64,
|
||||
}
|
||||
|
||||
pub struct PciAddressRange {
|
||||
pub ty: PciRangeType,
|
||||
pub bus_number: u8,
|
||||
pub pci_base: u64,
|
||||
pub host_base: PhysicalAddress,
|
||||
pub size: usize,
|
||||
}
|
||||
|
||||
/// Manager struct to store and control all PCI devices in the system
|
||||
pub struct PciBusManager {
|
||||
segments: Vec<PciBusSegment>,
|
||||
}
|
||||
|
||||
impl PciBaseAddress {
|
||||
pub fn as_memory(self) -> Option<PhysicalAddress> {
|
||||
match self {
|
||||
@ -416,6 +419,12 @@ impl PciBusSegment {
|
||||
}
|
||||
}
|
||||
|
||||
impl PciSegmentInfo {
|
||||
pub fn has_msi(&self) -> bool {
|
||||
!matches!(self.msi_translation_map, PciMsiMap::Legacy)
|
||||
}
|
||||
}
|
||||
|
||||
impl PciBusManager {
|
||||
const fn new() -> Self {
|
||||
Self {
|
||||
@ -463,7 +472,7 @@ impl PciBusManager {
|
||||
bus_number_end: 255,
|
||||
ecam_phys_base: None,
|
||||
irq_translation_map: PciInterruptMap::Legacy,
|
||||
has_msi: false,
|
||||
msi_translation_map: PciMsiMap::Legacy,
|
||||
}),
|
||||
allocator: None,
|
||||
devices: Vec::new(),
|
||||
@ -478,7 +487,12 @@ impl PciBusManager {
|
||||
|
||||
/// Enumerates a bus segment provided by ACPI MCFG table entry
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn add_segment_from_mcfg(entry: &McfgEntry) -> Result<(), Error> {
|
||||
pub fn add_segment_from_mcfg(
|
||||
entry: &McfgEntry,
|
||||
msi_controller: Arc<dyn MessageInterruptController>,
|
||||
) -> Result<(), Error> {
|
||||
let msi_translation_map = PciMsiMap::Identity(msi_controller);
|
||||
|
||||
let mut bus_segment = PciBusSegment {
|
||||
info: Arc::new(PciSegmentInfo {
|
||||
segment_number: entry.pci_segment_group as u8,
|
||||
@ -488,7 +502,7 @@ impl PciBusManager {
|
||||
|
||||
// TODO get the segment's PCI root bridge AML name
|
||||
irq_translation_map: PciInterruptMap::Acpi("\\_SB.PCI0._PRT".into()),
|
||||
has_msi: true,
|
||||
msi_translation_map,
|
||||
}),
|
||||
// Firmware done this for us
|
||||
allocator: None,
|
||||
@ -508,7 +522,8 @@ impl PciBusManager {
|
||||
cfg_base: PhysicalAddress,
|
||||
bus_range: core::ops::Range<u8>,
|
||||
ranges: Vec<PciAddressRange>,
|
||||
interrupt_map: PciInterruptMap,
|
||||
irq_translation_map: PciInterruptMap,
|
||||
msi_translation_map: PciMsiMap,
|
||||
) -> Result<(), Error> {
|
||||
let mut bus_segment = PciBusSegment {
|
||||
info: Arc::new(PciSegmentInfo {
|
||||
@ -517,8 +532,8 @@ impl PciBusManager {
|
||||
bus_number_end: bus_range.end,
|
||||
ecam_phys_base: Some(cfg_base),
|
||||
|
||||
irq_translation_map: interrupt_map,
|
||||
has_msi: false,
|
||||
irq_translation_map,
|
||||
msi_translation_map,
|
||||
}),
|
||||
allocator: Some(BusAddressAllocator::from_ranges(&ranges)),
|
||||
|
||||
|
@ -156,7 +156,7 @@ impl UsbDriver for UsbHidKeyboardDriver {
|
||||
let events = unsafe { MaybeUninit::slice_assume_init_ref(&events[..event_count]) };
|
||||
|
||||
for &event in events {
|
||||
log::info!("Generic Keyboard: {:?}", event);
|
||||
log::trace!("Generic Keyboard: {:?}", event);
|
||||
ygg_driver_input::send_event(event);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{device::Device, interrupt::InterruptHandler};
|
||||
use device_api::{
|
||||
device::Device,
|
||||
interrupt::{InterruptHandler, IrqVector},
|
||||
};
|
||||
use libk::error::Error;
|
||||
use libk_mm::{
|
||||
address::{AsPhysicalAddress, PhysicalAddress},
|
||||
@ -280,7 +283,7 @@ impl Rtl8139 {
|
||||
}
|
||||
|
||||
impl InterruptHandler for Rtl8139 {
|
||||
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
|
||||
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
|
||||
let regs = self.regs.lock();
|
||||
let status = regs.ISR.extract();
|
||||
// Clear ISR bits
|
||||
|
@ -4,7 +4,10 @@ use core::{
|
||||
};
|
||||
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
use device_api::{device::Device, interrupt::InterruptHandler};
|
||||
use device_api::{
|
||||
device::Device,
|
||||
interrupt::{InterruptHandler, IrqVector},
|
||||
};
|
||||
use libk::error::Error;
|
||||
use libk_mm::{
|
||||
address::{AsPhysicalAddress, PhysicalAddress},
|
||||
@ -255,7 +258,6 @@ impl RxRing {
|
||||
},
|
||||
capacity,
|
||||
)?;
|
||||
unsafe { core::arch::asm!("wbinvd") };
|
||||
Ok(Self {
|
||||
entries,
|
||||
buffers,
|
||||
@ -388,7 +390,6 @@ impl Descriptor {
|
||||
self.vlan_cmd = 0;
|
||||
unsafe {
|
||||
atomic::fence(Ordering::Release);
|
||||
core::arch::asm!("wbinvd");
|
||||
core::ptr::write_volatile(&mut self.cmd, cmd | Self::CMD_OWN);
|
||||
}
|
||||
}
|
||||
@ -400,7 +401,6 @@ impl Descriptor {
|
||||
self.vlan_cmd = 0;
|
||||
unsafe {
|
||||
atomic::fence(Ordering::Release);
|
||||
core::arch::asm!("wbinvd");
|
||||
core::ptr::write_volatile(&mut self.cmd, cmd);
|
||||
}
|
||||
}
|
||||
@ -545,7 +545,7 @@ impl Rtl8168 {
|
||||
}
|
||||
|
||||
impl InterruptHandler for Rtl8168 {
|
||||
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
|
||||
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
|
||||
let regs = self.regs.lock();
|
||||
let status = regs.ISR.extract();
|
||||
|
||||
@ -637,8 +637,6 @@ impl Device for Rtl8168 {
|
||||
|
||||
log::info!("rx_ring_base = {rx_ring_base:#x}");
|
||||
|
||||
unsafe { core::arch::asm!("wbinvd") };
|
||||
|
||||
// Setup Tx
|
||||
regs.TCR.modify(TCR::MXDMA::Unlimited);
|
||||
// Setup Rx
|
||||
|
@ -2,7 +2,10 @@ use core::sync::atomic::{AtomicU8, Ordering};
|
||||
|
||||
use alloc::{boxed::Box, collections::btree_map::BTreeMap, sync::Arc, vec::Vec};
|
||||
use async_trait::async_trait;
|
||||
use device_api::{device::Device, interrupt::InterruptHandler};
|
||||
use device_api::{
|
||||
device::Device,
|
||||
interrupt::{InterruptHandler, IrqVector},
|
||||
};
|
||||
use libk::{error::Error, task::runtime};
|
||||
use libk_mm::{
|
||||
address::{AsPhysicalAddress, PhysicalAddress},
|
||||
@ -480,7 +483,7 @@ impl Device for Xhci {
|
||||
}
|
||||
|
||||
impl InterruptHandler for Xhci {
|
||||
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
|
||||
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
|
||||
let status = self.regs.handle_interrupt(0);
|
||||
|
||||
if status.matches_all(USBSTS::HSE::SET) {
|
||||
|
@ -25,7 +25,6 @@ mod ring;
|
||||
mod util;
|
||||
|
||||
// Only x86-64 supports xHCI currently, because only it has MSI-X implemented
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pci_driver! {
|
||||
matches: [class (0x0C:0x03:0x30)],
|
||||
driver: {
|
||||
|
@ -9,7 +9,7 @@ use alloc::{collections::BTreeMap, sync::Arc};
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use device_api::{
|
||||
device::Device,
|
||||
interrupt::{InterruptAffinity, InterruptHandler},
|
||||
interrupt::{InterruptAffinity, InterruptHandler, IrqVector},
|
||||
};
|
||||
use libk_mm::PageBox;
|
||||
use libk_util::{
|
||||
@ -34,9 +34,6 @@ use yggdrasil_abi::{error::Error, net::MacAddress};
|
||||
struct Queues {
|
||||
receive: IrqSafeSpinlock<VirtQueue>,
|
||||
transmit: IrqSafeSpinlock<VirtQueue>,
|
||||
// #[allow(unused)]
|
||||
// configuration_vector: usize,
|
||||
receive_vector: Option<u16>,
|
||||
}
|
||||
|
||||
pub struct VirtioNet<T: Transport> {
|
||||
@ -202,7 +199,6 @@ impl<T: Transport + 'static> VirtioNet<T> {
|
||||
self.queues.init(Queues {
|
||||
receive: IrqSafeSpinlock::new(rx),
|
||||
transmit: IrqSafeSpinlock::new(tx),
|
||||
receive_vector,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
@ -232,39 +228,26 @@ impl<T: Transport + 'static> NetworkDevice for VirtioNet<T> {
|
||||
}
|
||||
|
||||
impl<T: Transport + 'static> InterruptHandler for VirtioNet<T> {
|
||||
fn handle_irq(self: Arc<Self>, vector: Option<usize>) -> bool {
|
||||
#[allow(clippy::redundant_pattern_matching)]
|
||||
if let Some(_) = vector {
|
||||
// MSI/MSI-X
|
||||
let Some(queues) = self.queues.try_get() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
if vector == queues.receive_vector.map(Into::into) {
|
||||
fn handle_irq(self: Arc<Self>, vector: IrqVector) -> bool {
|
||||
match vector {
|
||||
IrqVector::Msi(_) => {
|
||||
// MSI/MSI-X
|
||||
self.handle_receive_interrupt(0)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
// Legacy IRQ
|
||||
let (queue_irq, config_irq) = self.transport.lock().read_interrupt_status();
|
||||
IrqVector::Irq(_) => {
|
||||
// Legacy IRQ
|
||||
let (queue_irq, config_irq) = self.transport.lock().read_interrupt_status();
|
||||
|
||||
if queue_irq {
|
||||
self.handle_receive_interrupt(0);
|
||||
if queue_irq {
|
||||
self.handle_receive_interrupt(0);
|
||||
}
|
||||
|
||||
queue_irq || config_irq
|
||||
}
|
||||
|
||||
queue_irq || config_irq
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// impl<T: Transport + 'static> MsiHandler for VirtioNet<T> {
|
||||
// fn handle_msi(&self, vector: usize) -> bool {
|
||||
//
|
||||
// todo!()
|
||||
// }
|
||||
// }
|
||||
|
||||
impl<T: Transport + 'static> Device for VirtioNet<T> {
|
||||
fn display_name(&self) -> &str {
|
||||
"VirtIO Network Device"
|
||||
|
@ -61,6 +61,12 @@ pub enum InterruptAffinity {
|
||||
Specific(usize),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum IrqVector {
|
||||
Msi(usize),
|
||||
Irq(Irq),
|
||||
}
|
||||
|
||||
/// Describes messages sent from some CPU to others
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
#[repr(u64)]
|
||||
@ -73,7 +79,7 @@ pub enum IpiMessage {
|
||||
}
|
||||
|
||||
pub trait InterruptHandler: Device {
|
||||
fn handle_irq(self: Arc<Self>, vector: Option<usize>) -> bool;
|
||||
fn handle_irq(self: Arc<Self>, vector: IrqVector) -> bool;
|
||||
}
|
||||
|
||||
pub trait InterruptTable: Sync {
|
||||
@ -107,9 +113,9 @@ pub trait ExternalInterruptController: Device {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MessageInterruptController {
|
||||
pub trait MessageInterruptController: Device {
|
||||
fn register_msi(
|
||||
&self,
|
||||
self: Arc<Self>,
|
||||
affinity: InterruptAffinity,
|
||||
handler: Arc<dyn InterruptHandler>,
|
||||
) -> Result<MsiInfo, Error> {
|
||||
@ -123,7 +129,7 @@ pub trait MessageInterruptController {
|
||||
|
||||
#[allow(unused)]
|
||||
fn register_msi_range(
|
||||
&self,
|
||||
self: Arc<Self>,
|
||||
range: &mut [MsiInfo],
|
||||
handler: Arc<dyn InterruptHandler>,
|
||||
) -> Result<(), Error> {
|
||||
|
@ -7,16 +7,6 @@ use crate::TProp;
|
||||
|
||||
use super::{lookup_phandle, Node};
|
||||
|
||||
/// Looks up an `interrupt-controller` node by its phandle with lazy probe.
|
||||
pub fn interrupt_controller(phandle: Phandle) -> Option<Arc<Node>> {
|
||||
lookup_phandle(phandle, true)
|
||||
}
|
||||
|
||||
/// Looks up a clock controller by its phandle with lazy probe.
|
||||
pub fn clock_controller(phandle: Phandle) -> Option<Arc<Node>> {
|
||||
lookup_phandle(phandle, true)
|
||||
}
|
||||
|
||||
// Interrupt controller handling
|
||||
|
||||
/// Reads interrupt information, as interpreted by `interrupt_controller`, from `property` at a
|
||||
@ -33,7 +23,7 @@ pub fn map_interrupt_at(
|
||||
/// Same as [map_interrupt_at], but uses a phandle to address the `interrupt-controller` node
|
||||
/// and a scaled `index`.
|
||||
pub fn map_interrupt(phandle: Phandle, property: &TProp, index: usize) -> Option<FullIrq> {
|
||||
let interrupt_controller = interrupt_controller(phandle)?;
|
||||
let interrupt_controller = lookup_phandle(phandle, true)?;
|
||||
let interrupt_cells = interrupt_controller.self_interrupt_cells()?;
|
||||
map_interrupt_at(&interrupt_controller, property, index * interrupt_cells)
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ mod tree;
|
||||
|
||||
pub mod util;
|
||||
|
||||
pub use controller::{interrupt_controller, map_interrupt, map_interrupt_at};
|
||||
pub use controller::{map_interrupt, map_interrupt_at};
|
||||
pub use macros::device_tree_driver;
|
||||
pub use registry::{lookup_phandle, register_driver};
|
||||
pub use traits::{DeviceTreeInterruptController, Driver, ProbeContext};
|
||||
|
@ -2,7 +2,11 @@
|
||||
use core::ops::Range;
|
||||
|
||||
use alloc::sync::{Arc, Weak};
|
||||
use device_api::{bus::Bus, device::Device, interrupt::FullIrq};
|
||||
use device_api::{
|
||||
bus::Bus,
|
||||
device::Device,
|
||||
interrupt::{ExternalInterruptController, FullIrq},
|
||||
};
|
||||
|
||||
use crate::TProp;
|
||||
|
||||
@ -19,6 +23,9 @@ pub trait DeviceTreeInterruptController {
|
||||
/// Reads interrupt information from `property` at given `offset` and maps it to
|
||||
/// the interrupt used by the controller
|
||||
fn map_interrupt(&self, property: &TProp, offset: usize) -> Option<FullIrq>;
|
||||
|
||||
/// Returns the [ExternalInterruptController] implementor of this node
|
||||
fn as_interrupt_controller(self: Arc<Self>) -> Arc<dyn ExternalInterruptController>;
|
||||
}
|
||||
|
||||
/// Context passed to the driver's `probe` function
|
||||
|
@ -5,7 +5,12 @@ use alloc::{
|
||||
sync::{Arc, Weak},
|
||||
vec::Vec,
|
||||
};
|
||||
use device_api::{bus::Bus, clock::ClockController, device::Device, interrupt::FullIrq};
|
||||
use device_api::{
|
||||
bus::Bus,
|
||||
clock::ClockController,
|
||||
device::Device,
|
||||
interrupt::{ExternalInterruptController, FullIrq, MessageInterruptController},
|
||||
};
|
||||
use fdt_rs::spec::Phandle;
|
||||
use libk_mm::address::PhysicalAddress;
|
||||
use libk_util::OneTimeInit;
|
||||
@ -42,6 +47,7 @@ pub struct Node {
|
||||
device: OneTimeInit<NodeDevice>,
|
||||
init_token: OneTimeInit<()>,
|
||||
pub(crate) interrupt_controller: OneTimeInit<Arc<dyn DeviceTreeInterruptController>>,
|
||||
pub(crate) msi_controller: OneTimeInit<Arc<dyn MessageInterruptController>>,
|
||||
}
|
||||
|
||||
enum NodeDevice {
|
||||
@ -157,6 +163,12 @@ impl Node {
|
||||
self.interrupt_controller.init(intc);
|
||||
}
|
||||
|
||||
/// When called from an msi-controller driver, informs the node of its capability as an MSI
|
||||
/// controller.
|
||||
pub fn make_msi_controller(&self, intc: Arc<dyn MessageInterruptController>) {
|
||||
self.msi_controller.init(intc);
|
||||
}
|
||||
|
||||
/// Returns the device driver associated with this node, if any was probed.
|
||||
pub fn driver(&self) -> Option<&'static dyn Driver> {
|
||||
self.device.try_get()?.driver()
|
||||
@ -290,6 +302,13 @@ impl Node {
|
||||
device.as_device()?.as_clock_controller()
|
||||
}
|
||||
|
||||
/// Attempts to get an interrupt controller represented by this node, if any
|
||||
pub fn as_interrupt_controller(&self) -> Option<Arc<dyn ExternalInterruptController>> {
|
||||
self.interrupt_controller
|
||||
.try_get()
|
||||
.map(|e| e.clone().as_interrupt_controller())
|
||||
}
|
||||
|
||||
/// Returns the `#address-cells` value of the node's parent bus
|
||||
pub fn bus_address_cells(&self) -> usize {
|
||||
self.bus_address_cells
|
||||
@ -368,6 +387,7 @@ fn unflatten_node(
|
||||
device: OneTimeInit::new(),
|
||||
init_token: OneTimeInit::new(),
|
||||
interrupt_controller: OneTimeInit::new(),
|
||||
msi_controller: OneTimeInit::new(),
|
||||
});
|
||||
|
||||
if let Some(phandle) = phandle {
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! General helpers and utilities for device tree drivers
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use device_api::interrupt::FullIrq;
|
||||
use device_api::interrupt::{FullIrq, MessageInterruptController};
|
||||
|
||||
use crate::{
|
||||
driver::{lookup_phandle, map_interrupt_at},
|
||||
@ -27,6 +27,22 @@ pub struct PcieInterruptEntry {
|
||||
pub irq: FullIrq,
|
||||
}
|
||||
|
||||
/// Represents a single PCI address (Requester ID for a MSI(-x))
|
||||
#[derive(Debug)]
|
||||
pub struct PcieMsiRequesterId(u32);
|
||||
|
||||
/// Represents an entry in a PCIe-controller's `msi-map` field
|
||||
pub struct PcieMsiEntry {
|
||||
/// Base requester ID
|
||||
pub base_rid: PcieMsiRequesterId,
|
||||
/// Number of consecutive Requester IDs this entry describes
|
||||
pub length: u32,
|
||||
/// MSI controller this entry maps to
|
||||
pub msi_controller: Arc<dyn MessageInterruptController>,
|
||||
/// Base vector this entry translates to in the MSI controller
|
||||
pub msi_base: u32,
|
||||
}
|
||||
|
||||
/// An iterator over a generic PCIe interrupt map
|
||||
pub struct PcieInterruptMapIter<'a> {
|
||||
interrupt_map: TProp<'a>,
|
||||
@ -34,6 +50,12 @@ pub struct PcieInterruptMapIter<'a> {
|
||||
child_address_cells: usize,
|
||||
}
|
||||
|
||||
/// An iterator over a generic PCIe MSI map
|
||||
pub struct PcieMsiMapIter<'a> {
|
||||
msi_map: TProp<'a>,
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
impl Iterator for PcieInterruptMapIter<'_> {
|
||||
type Item = PcieInterruptEntry;
|
||||
|
||||
@ -88,6 +110,56 @@ impl Iterator for PcieInterruptMapIter<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for PcieMsiMapIter<'_> {
|
||||
type Item = PcieMsiEntry;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.offset >= self.msi_map.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Each entry is 4 cells:
|
||||
//
|
||||
// * Requester ID (PCI address) base
|
||||
// * msi-controller node phandle
|
||||
// * msi-base
|
||||
// * Number of consecutive Requester ID for this entry
|
||||
|
||||
let (base_rid, phandle, msi_base, length) =
|
||||
self.msi_map.read_cells_at(self.offset, (1, 1, 1, 1))?;
|
||||
let base_rid = PcieMsiRequesterId(base_rid as u32);
|
||||
let msi_controller = lookup_phandle(phandle as u32, true)?;
|
||||
let msi_controller = msi_controller.msi_controller.try_get()?.clone();
|
||||
let msi_base = msi_base as u32;
|
||||
let length = length as u32;
|
||||
|
||||
self.offset += 4;
|
||||
|
||||
Some(PcieMsiEntry {
|
||||
base_rid,
|
||||
msi_base,
|
||||
msi_controller,
|
||||
length,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl PcieMsiRequesterId {
|
||||
/// Splits the struct into bus:device:function parts
|
||||
pub fn as_parts(&self) -> (u8, u8, u8) {
|
||||
let bus = (self.0 >> 8) as u8;
|
||||
let device = ((self.0 >> 3) & 0x1F) as u8;
|
||||
let function = (self.0 & 0xF) as u8;
|
||||
|
||||
(bus, device, function)
|
||||
}
|
||||
|
||||
/// Applies an offset to this requester ID, returning the result
|
||||
pub fn offset(&self, offset: u32) -> Self {
|
||||
Self(self.0 + offset - 1)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator over the PCIe-controller's `interrupt-map`
|
||||
pub fn pcie_interrupt_map(node: &Arc<Node>) -> Option<PcieInterruptMapIter<'static>> {
|
||||
let interrupt_map = node.property("interrupt-map")?;
|
||||
@ -99,3 +171,9 @@ pub fn pcie_interrupt_map(node: &Arc<Node>) -> Option<PcieInterruptMapIter<'stat
|
||||
offset: 0,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns an iterator over the PCIe-controller's `msi-map`
|
||||
pub fn pcie_msi_map(node: &Arc<Node>) -> Option<PcieMsiMapIter<'static>> {
|
||||
let msi_map = node.property("msi-map")?;
|
||||
Some(PcieMsiMapIter { msi_map, offset: 0 })
|
||||
}
|
||||
|
@ -1,13 +1,6 @@
|
||||
// pub mod display;
|
||||
|
||||
// pub use libk_device::*;
|
||||
|
||||
use alloc::sync::Arc;
|
||||
|
||||
use device_api::interrupt::{
|
||||
ExternalInterruptController, InterruptHandler, Irq, IrqOptions, MessageInterruptController,
|
||||
};
|
||||
use kernel_arch::{Architecture, ArchitectureImpl};
|
||||
use device_api::interrupt::ExternalInterruptController;
|
||||
use libk_util::OneTimeInit;
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
@ -16,6 +9,7 @@ pub mod char;
|
||||
pub mod display;
|
||||
pub mod manager;
|
||||
|
||||
// TODO get rid of this, this does not work when there are multiple interrupt controllers
|
||||
// Interrupt controllers don't disappear (or at least in my OS), so it's okay to keep a reference
|
||||
// inside a static OneTimeInit.
|
||||
static EXTERNAL_INTC: OneTimeInit<Arc<dyn ExternalInterruptController>> = OneTimeInit::new();
|
||||
@ -28,23 +22,3 @@ pub fn external_interrupt_controller(
|
||||
) -> Result<&'static Arc<dyn ExternalInterruptController>, Error> {
|
||||
EXTERNAL_INTC.try_get().ok_or(Error::DoesNotExist)
|
||||
}
|
||||
|
||||
pub fn message_interrupt_controller() -> Result<&'static dyn MessageInterruptController, Error> {
|
||||
ArchitectureImpl::message_interrupt_controller().ok_or(Error::DoesNotExist)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn register_global_interrupt(
|
||||
irq: u32,
|
||||
options: IrqOptions,
|
||||
handler: Arc<dyn InterruptHandler>,
|
||||
) -> Result<(), Error> {
|
||||
let intc = external_interrupt_controller()?;
|
||||
|
||||
let irq = Irq::External(irq);
|
||||
|
||||
intc.register_irq(irq, options, handler)?;
|
||||
intc.enable_irq(irq)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -9,7 +9,8 @@ use tock_registers::{
|
||||
register_bitfields! {
|
||||
u32,
|
||||
CTLR [
|
||||
Enable OFFSET(0) NUMBITS(1) []
|
||||
EnableGrp0 OFFSET(0) NUMBITS(1) [],
|
||||
EnableGrp1 OFFSET(1) NUMBITS(1) [],
|
||||
],
|
||||
PMR [
|
||||
Priority OFFSET(0) NUMBITS(8) []
|
||||
@ -45,7 +46,9 @@ impl Gicc {
|
||||
|
||||
pub unsafe fn init(&self) {
|
||||
log::debug!("Enabling GICv2 GICC");
|
||||
self.regs.CTLR.write(CTLR::Enable::SET);
|
||||
self.regs
|
||||
.CTLR
|
||||
.write(CTLR::EnableGrp0::SET + CTLR::EnableGrp1::SET);
|
||||
self.regs.PMR.write(PMR::Priority.val(0xFF));
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
//! ARM GICv2 Distributor registers
|
||||
use device_api::interrupt::{IpiDeliveryTarget, IrqLevel, IrqOptions, IrqTrigger};
|
||||
use device_api::interrupt::{IpiDeliveryTarget, IrqOptions, IrqTrigger};
|
||||
use libk_mm::device::DeviceMemoryIo;
|
||||
use libk_util::sync::Spinlock;
|
||||
use tock_registers::{
|
||||
@ -11,7 +11,9 @@ use tock_registers::{
|
||||
register_bitfields! {
|
||||
u32,
|
||||
CTLR [
|
||||
Enable OFFSET(0) NUMBITS(1) []
|
||||
EnableGrp0 OFFSET(0) NUMBITS(1) [],
|
||||
EnableGrp1NS OFFSET(1) NUMBITS(1) [],
|
||||
ARE_NS OFFSET(5) NUMBITS(1) [],
|
||||
],
|
||||
TYPER [
|
||||
ITLinesNumber OFFSET(0) NUMBITS(5) []
|
||||
@ -39,8 +41,14 @@ register_structs! {
|
||||
(0x000 => CTLR: ReadWrite<u32, CTLR::Register>),
|
||||
(0x004 => TYPER: ReadWrite<u32, TYPER::Register>),
|
||||
(0x008 => _0),
|
||||
(0x040 => SETSPI_NSR: WriteOnly<u32>),
|
||||
(0x044 => _7),
|
||||
(0x084 => IGROUPRn: [ReadWrite<u32>; 31]),
|
||||
(0x100 => _5),
|
||||
(0x104 => ISENABLER: [ReadWrite<u32>; 31]),
|
||||
(0x180 => _1),
|
||||
(0x420 => IPRIORITYRn: [ReadWrite<u32>; 248]),
|
||||
(0x800 => _6),
|
||||
(0x820 => ITARGETSR: [ReadWrite<u32, ITARGETSR::Register>; 248]),
|
||||
(0xC00 => _2),
|
||||
(0xC08 => ICFGR: [ReadWrite<u32>; 62]),
|
||||
@ -76,12 +84,7 @@ impl GicdSharedRegs {
|
||||
|
||||
#[inline(always)]
|
||||
fn itargets_slice(&self) -> &[ReadWrite<u32, ITARGETSR::Register>] {
|
||||
if self.num_irqs() >= 36 {
|
||||
let itargetsr_max_index = ((self.num_irqs() - 32) >> 2) - 1;
|
||||
&self.ITARGETSR[0..itargetsr_max_index]
|
||||
} else {
|
||||
&[]
|
||||
}
|
||||
&self.ITARGETSR[..]
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,11 +123,9 @@ impl Gicd {
|
||||
// 2 bits per IRQ, 16 entries per register
|
||||
let reg = irq / 16;
|
||||
let shift = (irq % 16) * 2;
|
||||
let cfgr_value = match (options.trigger, options.level) {
|
||||
(IrqTrigger::Level, IrqLevel::ActiveLow) => 0,
|
||||
(IrqTrigger::Level, _) => 0,
|
||||
(_, IrqLevel::ActiveLow) => 1,
|
||||
(_, _) => 1,
|
||||
let cfgr_value = match options.trigger {
|
||||
IrqTrigger::Edge | IrqTrigger::Default => 0b10,
|
||||
IrqTrigger::Level => 0b00,
|
||||
};
|
||||
|
||||
match reg {
|
||||
@ -170,7 +171,7 @@ impl Gicd {
|
||||
|
||||
log::debug!("Enabling GICv2 GICD, max IRQ number: {}", regs.num_irqs());
|
||||
|
||||
regs.CTLR.modify(CTLR::Enable::SET);
|
||||
regs.CTLR.modify(CTLR::EnableGrp0::SET);
|
||||
|
||||
for reg in regs.itargets_slice().iter() {
|
||||
// Redirect all IRQs to cpu0 (this CPU)
|
||||
|
259
kernel/src/arch/aarch64/gic/gicv2m.rs
Normal file
259
kernel/src/arch/aarch64/gic/gicv2m.rs
Normal file
@ -0,0 +1,259 @@
|
||||
//! ARM GICv2m extension support for MSI/MSI-x
|
||||
use core::{mem::offset_of, ops::Range};
|
||||
|
||||
use abi::error::Error;
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
use device_api::{
|
||||
device::Device,
|
||||
interrupt::{
|
||||
ExternalInterruptController, InterruptAffinity, InterruptHandler, Irq, IrqLevel,
|
||||
IrqOptions, IrqTrigger, IrqVector, MessageInterruptController, MsiInfo,
|
||||
},
|
||||
};
|
||||
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
|
||||
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
|
||||
use libk_util::{
|
||||
sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock},
|
||||
OneTimeInit,
|
||||
};
|
||||
use tock_registers::{
|
||||
interfaces::Readable,
|
||||
register_bitfields, register_structs,
|
||||
registers::{ReadOnly, WriteOnly},
|
||||
};
|
||||
|
||||
use crate::arch::aarch64::gic::GIC_SPI_START;
|
||||
|
||||
register_bitfields! {
|
||||
u32,
|
||||
GICM_TYPER [
|
||||
VALID OFFSET(31) NUMBITS(1) [],
|
||||
CLR OFFSET(30) NUMBITS(1) [],
|
||||
SR OFFSET(29) NUMBITS(1) [],
|
||||
INTID OFFSET(16) NUMBITS(13) [],
|
||||
NUMSPIS OFFSET(0) NUMBITS(11) [],
|
||||
],
|
||||
GICM_IIDR [
|
||||
VARIANT OFFSET(16) NUMBITS(4) [],
|
||||
REVISION OFFSET(12) NUMBITS(4) [],
|
||||
IMPLEMENTER OFFSET(0) NUMBITS(12) [],
|
||||
],
|
||||
}
|
||||
|
||||
register_structs! {
|
||||
#[allow(non_snake_case)]
|
||||
Regs {
|
||||
(0x0000 => _0),
|
||||
(0x0008 => GICM_TYPER: ReadOnly<u32, GICM_TYPER::Register>),
|
||||
(0x000C => _1),
|
||||
(0x0040 => GICM_SETSPI_NSR: WriteOnly<u32>),
|
||||
(0x0044 => _2),
|
||||
(0x0048 => GICM_CLRSPI_NSR: WriteOnly<u32>),
|
||||
(0x004C => _3),
|
||||
(0x0050 => GICM_SETSPI_SR: WriteOnly<u32>),
|
||||
(0x0054 => _4),
|
||||
(0x0058 => GICM_CLRSPI_SR: WriteOnly<u32>),
|
||||
(0x005C => _5),
|
||||
(0x0FCC => GICM_IIDR: ReadOnly<u32, GICM_IIDR::Register>),
|
||||
(0x0FD0 => _6),
|
||||
(0x1000 => @END),
|
||||
}
|
||||
}
|
||||
|
||||
struct MsiEntry {
|
||||
handler: Arc<dyn InterruptHandler>,
|
||||
vector: usize,
|
||||
}
|
||||
|
||||
struct Inner {
|
||||
irq_range: Range<u32>,
|
||||
msi_map: IrqSafeRwLock<Vec<Option<MsiEntry>>>,
|
||||
}
|
||||
|
||||
/// GICv2m Register Frame, allows handling MSI(-x)-based interrupts via its parent GIC
|
||||
pub struct Gicv2m {
|
||||
base: PhysicalAddress,
|
||||
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
|
||||
parent: Arc<dyn ExternalInterruptController>,
|
||||
|
||||
msi_base_override: Option<u32>,
|
||||
msi_count_override: Option<usize>,
|
||||
|
||||
inner: OneTimeInit<Inner>,
|
||||
}
|
||||
|
||||
impl Device for Gicv2m {
|
||||
unsafe fn init(self: Arc<Self>) -> Result<(), Error> {
|
||||
let regs = self.regs.lock();
|
||||
log::info!("gicv2m: init @ {:#x}", self.base);
|
||||
|
||||
// NOTE qemu's gicv2m TYPER.VALID = 0 for some reason, even though it contains proper
|
||||
// values
|
||||
let quirk_qemu = (regs.GICM_IIDR.get() >> 20) == b'Q' as u32;
|
||||
|
||||
// If GICM_TYPER.VALID == 0, use the base provided via device tree (or fail if neither is
|
||||
// available)
|
||||
let valid = quirk_qemu || regs.GICM_TYPER.matches_all(GICM_TYPER::VALID::SET);
|
||||
|
||||
let irq_base = if valid {
|
||||
regs.GICM_TYPER.read(GICM_TYPER::INTID)
|
||||
} else {
|
||||
self.msi_base_override
|
||||
.ok_or(Error::InvalidArgument)
|
||||
.inspect_err(|_| {
|
||||
log::error!("gicv2m: typer is not valid and no base provided in the FDT")
|
||||
})?
|
||||
};
|
||||
let irq_count = if valid {
|
||||
regs.GICM_TYPER.read(GICM_TYPER::NUMSPIS)
|
||||
} else {
|
||||
self.msi_count_override
|
||||
.ok_or(Error::InvalidArgument)
|
||||
.inspect_err(|_| {
|
||||
log::error!("gicv2m: typer is not valid and no irq count provided in the FDT")
|
||||
})? as u32
|
||||
};
|
||||
|
||||
log::info!("gicv2m: irq base {irq_base}, irq count {irq_count}");
|
||||
let irq_range = irq_base..irq_base + irq_count;
|
||||
self.inner.init(Inner {
|
||||
irq_range: irq_range.clone(),
|
||||
msi_map: IrqSafeRwLock::new((0..irq_count as usize).map(|_| None).collect()),
|
||||
});
|
||||
|
||||
for irq in irq_range {
|
||||
// Map SPI in parent
|
||||
let irq = Irq::External(irq - 32);
|
||||
self.parent.register_irq(
|
||||
irq,
|
||||
IrqOptions {
|
||||
trigger: IrqTrigger::Edge,
|
||||
level: IrqLevel::ActiveHigh,
|
||||
},
|
||||
self.clone(),
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn display_name(&self) -> &str {
|
||||
"GICv2m Frame"
|
||||
}
|
||||
}
|
||||
|
||||
impl InterruptHandler for Gicv2m {
|
||||
fn handle_irq(self: Arc<Self>, vector: IrqVector) -> bool {
|
||||
let IrqVector::Irq(Irq::External(spi)) = vector else {
|
||||
return false;
|
||||
};
|
||||
let Some(inner) = self.inner.try_get() else {
|
||||
return false;
|
||||
};
|
||||
let msi_map = inner.msi_map.read();
|
||||
let index = (spi + GIC_SPI_START - inner.irq_range.start) as usize;
|
||||
if index >= inner.irq_range.len() {
|
||||
return false;
|
||||
}
|
||||
if let Some(entry) = &msi_map[index] {
|
||||
entry
|
||||
.handler
|
||||
.clone()
|
||||
.handle_irq(IrqVector::Msi(entry.vector))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MessageInterruptController for Gicv2m {
|
||||
fn handle_msi(&self, _vector: usize) {
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn register_msi_range(
|
||||
self: Arc<Self>,
|
||||
range: &mut [MsiInfo],
|
||||
handler: Arc<dyn InterruptHandler>,
|
||||
) -> Result<(), Error> {
|
||||
let inner = self.inner.get();
|
||||
let mut msi_map = inner.msi_map.write();
|
||||
// let map = self.irq_map.write();
|
||||
// let irq_range = self.irq_range.try_get().ok_or(Error::DoesNotExist)?.clone();
|
||||
let irq_base = inner.irq_range.start;
|
||||
|
||||
let mut allocated_range = None;
|
||||
for irq in inner.irq_range.clone() {
|
||||
let mut taken = false;
|
||||
for i in 0..range.len() {
|
||||
let index = (irq - irq_base) as usize + i;
|
||||
if msi_map[index].is_some() {
|
||||
taken = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if taken {
|
||||
continue;
|
||||
}
|
||||
|
||||
allocated_range = Some(irq..irq + range.len() as u32);
|
||||
break;
|
||||
}
|
||||
|
||||
let map_range = allocated_range
|
||||
.ok_or(Error::InvalidArgument)
|
||||
.inspect_err(|_| log::warn!("gicv2m: no free irq slots"))?;
|
||||
|
||||
for (i, (info, irq)) in core::iter::zip(range, map_range).enumerate() {
|
||||
log::info!("gicv2m: map msi irq {irq} -> {}", handler.display_name());
|
||||
let index = (irq - irq_base) as usize;
|
||||
|
||||
msi_map[index] = Some(MsiEntry {
|
||||
vector: i,
|
||||
handler: handler.clone(),
|
||||
});
|
||||
|
||||
*info = MsiInfo {
|
||||
address: self
|
||||
.base
|
||||
.add(offset_of!(Regs, GICM_SETSPI_NSR))
|
||||
.into_usize(),
|
||||
value: irq,
|
||||
vector: i,
|
||||
affinity: InterruptAffinity::Any,
|
||||
};
|
||||
self.parent.enable_irq(Irq::External(irq - 32))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
device_tree_driver! {
|
||||
compatible: ["arm,gic-v2m-frame"],
|
||||
driver: {
|
||||
fn probe(&self, node: &Arc<Node>, context: &ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
let base = node.map_base(context, 0)?;
|
||||
let parent = node.parent()?.as_interrupt_controller()?;
|
||||
|
||||
let msi_base_override = node.prop_usize("arm,msi-base-spi").map(|x| x as u32);
|
||||
let msi_count_override = node.prop_usize("arm,msi-num-spis");
|
||||
|
||||
let regs = unsafe { DeviceMemoryIo::map(base, Default::default()) }.inspect_err(|e| {
|
||||
log::error!("gicv2m: could not map memory at {base:#x}: {e:?}");
|
||||
}).ok()?;
|
||||
|
||||
let intc = Arc::new(Gicv2m {
|
||||
base,
|
||||
parent,
|
||||
msi_base_override,
|
||||
msi_count_override,
|
||||
regs: IrqSafeSpinlock::new(regs),
|
||||
inner: OneTimeInit::new()
|
||||
});
|
||||
|
||||
node.make_msi_controller(intc.clone());
|
||||
Some(intc)
|
||||
}
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@ use device_api::{
|
||||
interrupt::{
|
||||
ExternalInterruptController, FixedInterruptTable, FullIrq, InterruptHandler,
|
||||
InterruptTable, IpiDeliveryTarget, IpiMessage, Irq, IrqLevel, IrqOptions, IrqTrigger,
|
||||
LocalInterruptController, MessageInterruptController, MsiInfo,
|
||||
IrqVector, LocalInterruptController,
|
||||
},
|
||||
};
|
||||
use device_tree::{
|
||||
@ -32,8 +32,12 @@ use super::AArch64;
|
||||
const MAX_IRQ: usize = 300;
|
||||
const IPI_VECTOR: u64 = 1;
|
||||
|
||||
const GIC_PPI_START: u32 = 16;
|
||||
const GIC_SPI_START: u32 = 32;
|
||||
|
||||
pub mod gicc;
|
||||
pub mod gicd;
|
||||
pub mod gicv2m;
|
||||
|
||||
/// ARM Generic Interrupt Controller v2
|
||||
pub struct Gic {
|
||||
@ -96,8 +100,8 @@ impl ExternalInterruptController for Gic {
|
||||
let gicd = self.gicd.get();
|
||||
|
||||
let index = match irq {
|
||||
Irq::External(i) => i + 32,
|
||||
Irq::Private(i) => i + 16,
|
||||
Irq::External(i) => i + GIC_SPI_START,
|
||||
Irq::Private(i) => i + GIC_PPI_START,
|
||||
} as usize;
|
||||
|
||||
log::debug!(
|
||||
@ -107,7 +111,7 @@ impl ExternalInterruptController for Gic {
|
||||
options.trigger,
|
||||
options.level
|
||||
);
|
||||
if index >= 32 {
|
||||
if index >= GIC_SPI_START as usize {
|
||||
gicd.configure_irq(index, options);
|
||||
}
|
||||
table.insert(index, handler)?;
|
||||
@ -118,28 +122,38 @@ impl ExternalInterruptController for Gic {
|
||||
fn enable_irq(&self, irq: Irq) -> Result<(), Error> {
|
||||
let gicd = self.gicd.get();
|
||||
let index = match irq {
|
||||
Irq::External(i) => i + 32,
|
||||
Irq::Private(i) => i + 16,
|
||||
Irq::External(i) => i + GIC_SPI_START,
|
||||
Irq::Private(i) => i + GIC_PPI_START,
|
||||
} as usize;
|
||||
log::info!("Enable irq{index} ({irq:?})");
|
||||
log::debug!("Enable irq{index} ({irq:?})");
|
||||
gicd.enable_irq(index);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_pending_irqs(&self) {
|
||||
let gicc = self.gicc.get();
|
||||
|
||||
let irq_number = gicc.pending_irq_number();
|
||||
if irq_number >= MAX_IRQ {
|
||||
return;
|
||||
}
|
||||
|
||||
gicc.clear_irq(irq_number);
|
||||
|
||||
if irq_number == IPI_VECTOR as usize {
|
||||
gicc.clear_irq(irq_number);
|
||||
// TODO pop entry
|
||||
crate::panic::panic_secondary();
|
||||
}
|
||||
|
||||
gicc.clear_irq(irq_number);
|
||||
if irq_number < GIC_PPI_START as usize {
|
||||
return;
|
||||
}
|
||||
|
||||
let irq = if irq_number < GIC_SPI_START as usize {
|
||||
Irq::Private(irq_number as u32 - GIC_PPI_START)
|
||||
} else {
|
||||
Irq::External(irq_number as u32 - GIC_SPI_START)
|
||||
};
|
||||
|
||||
{
|
||||
let table = self.table.read();
|
||||
@ -151,25 +165,11 @@ impl ExternalInterruptController for Gic {
|
||||
}
|
||||
};
|
||||
|
||||
entry.handle_irq(None);
|
||||
entry.handle_irq(IrqVector::Irq(irq));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MessageInterruptController for Gic {
|
||||
fn handle_msi(&self, _vector: usize) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn register_msi_range(
|
||||
&self,
|
||||
_range: &mut [MsiInfo],
|
||||
_handler: Arc<dyn InterruptHandler>,
|
||||
) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl LocalInterruptController for Gic {
|
||||
fn send_ipi(&self, target: IpiDeliveryTarget, msg: IpiMessage) -> Result<(), Error> {
|
||||
let local = cpu_index();
|
||||
@ -211,8 +211,6 @@ impl DeviceTreeInterruptController for Gic {
|
||||
// IRQ_TYPE_LEVEL_HIGH - 4
|
||||
// IRQ_TYPE_LEVEL_LOW - 8
|
||||
|
||||
log::info!("MAP INTERRUPT offset={offset}");
|
||||
|
||||
let sizes = (1, 1, 1);
|
||||
let (kind, number, options) = property.read_cells_at(offset, sizes)?;
|
||||
let number = number as u32;
|
||||
@ -236,6 +234,10 @@ impl DeviceTreeInterruptController for Gic {
|
||||
options: IrqOptions { trigger, level },
|
||||
})
|
||||
}
|
||||
|
||||
fn as_interrupt_controller(self: Arc<Self>) -> Arc<dyn ExternalInterruptController> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Gic {
|
||||
|
@ -7,7 +7,7 @@ use abi::{error::Error, time::NANOSECONDS_IN_SECOND};
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
device::Device,
|
||||
interrupt::{FullIrq, InterruptHandler},
|
||||
interrupt::{FullIrq, InterruptHandler, IrqVector},
|
||||
};
|
||||
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
|
||||
use kernel_arch::task::Scheduler;
|
||||
@ -25,7 +25,7 @@ pub const TICK_INTERVAL: u64 = 250000;
|
||||
static LAST_TICKS: AtomicU64 = AtomicU64::new(0);
|
||||
|
||||
impl InterruptHandler for ArmTimer {
|
||||
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
|
||||
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
|
||||
let count = CNTPCT_EL0.get();
|
||||
|
||||
CNTP_TVAL_EL0.set(TICK_INTERVAL);
|
||||
|
@ -5,7 +5,7 @@ use acpi::HpetInfo;
|
||||
use alloc::{collections::btree_map::BTreeMap, format, string::String, sync::Arc};
|
||||
use device_api::{
|
||||
device::Device,
|
||||
interrupt::{InterruptHandler, Irq, IrqOptions, IrqTrigger},
|
||||
interrupt::{InterruptHandler, Irq, IrqOptions, IrqTrigger, IrqVector},
|
||||
};
|
||||
use libk::{device::external_interrupt_controller, task::runtime, time};
|
||||
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
|
||||
@ -102,7 +102,7 @@ const FS_IN_S: u64 = 10u64.pow(15);
|
||||
const FS_IN_NS: u64 = 10u64.pow(6);
|
||||
|
||||
impl InterruptHandler for HpetTimer {
|
||||
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
|
||||
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
|
||||
let now = self.parent.read_counter();
|
||||
let last = self.last_ticks.swap(now, Ordering::Relaxed);
|
||||
let delta = now.wrapping_sub(last);
|
||||
|
@ -2,7 +2,7 @@ use abi::error::Error;
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
device::Device,
|
||||
interrupt::{InterruptHandler, Irq},
|
||||
interrupt::{InterruptHandler, Irq, IrqVector},
|
||||
};
|
||||
use kernel_arch_x86::{
|
||||
intrinsics::{IoPort, IoPortAccess},
|
||||
@ -31,7 +31,7 @@ pub struct I8253 {
|
||||
}
|
||||
|
||||
impl InterruptHandler for I8253 {
|
||||
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
|
||||
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
|
||||
self.irq_handler_fastpath();
|
||||
true
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use device_api::{
|
||||
device::Device,
|
||||
interrupt::{
|
||||
ExternalInterruptController, FixedInterruptTable, InterruptHandler, InterruptTable, Irq,
|
||||
IrqOptions,
|
||||
IrqOptions, IrqVector,
|
||||
},
|
||||
};
|
||||
use kernel_arch_x86::intrinsics::{IoPort, IoPortAccess};
|
||||
@ -94,9 +94,10 @@ impl ExternalInterruptController for I8259 {
|
||||
self.eoi(index);
|
||||
|
||||
let table = self.table.lock();
|
||||
let vector = IrqVector::Irq(Irq::External(index as u32));
|
||||
|
||||
if let Some(handler) = table.handler(index - 1) {
|
||||
handler.clone().handle_irq(None);
|
||||
handler.clone().handle_irq(vector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use abi::{
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
device::Device,
|
||||
interrupt::{InterruptHandler, Irq},
|
||||
interrupt::{InterruptHandler, Irq, IrqVector},
|
||||
};
|
||||
use kernel_arch_x86::{
|
||||
intrinsics::{IoPort, IoPortAccess},
|
||||
@ -76,7 +76,7 @@ impl Inner {
|
||||
}
|
||||
|
||||
impl InterruptHandler for PS2Controller {
|
||||
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
|
||||
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
|
||||
let mut count = 0;
|
||||
let mut inner = self.inner.lock();
|
||||
|
||||
|
@ -2,7 +2,7 @@ use abi::error::Error;
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
device::Device,
|
||||
interrupt::{InterruptHandler, Irq},
|
||||
interrupt::{InterruptHandler, Irq, IrqVector},
|
||||
};
|
||||
use kernel_arch::{Architecture, ArchitectureImpl};
|
||||
use kernel_arch_x86::{
|
||||
@ -124,7 +124,7 @@ impl Inner {
|
||||
}
|
||||
|
||||
impl InterruptHandler for Rtc {
|
||||
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
|
||||
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
|
||||
let mut inner = self.inner.lock();
|
||||
if inner.counter == 0 {
|
||||
let time = inner.read_date_time();
|
||||
|
@ -3,7 +3,7 @@ use abi::{error::Error, io::TerminalOptions};
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
device::Device,
|
||||
interrupt::{InterruptHandler, Irq},
|
||||
interrupt::{InterruptHandler, Irq, IrqVector},
|
||||
};
|
||||
use kernel_arch_x86::intrinsics::{IoPort, IoPortAccess};
|
||||
use libk::{
|
||||
@ -97,7 +97,7 @@ impl DebugSink for Port {
|
||||
}
|
||||
|
||||
impl InterruptHandler for Port {
|
||||
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
|
||||
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
|
||||
let inner = self.terminal.output();
|
||||
if let Some(byte) = inner.handle_irq() {
|
||||
self.terminal.write_to_input(byte);
|
||||
|
@ -6,7 +6,7 @@ use device_api::{
|
||||
device::Device,
|
||||
interrupt::{
|
||||
ExternalInterruptController, FixedInterruptTable, InterruptHandler, InterruptTable, Irq,
|
||||
IrqLevel, IrqOptions, IrqTrigger,
|
||||
IrqLevel, IrqOptions, IrqTrigger, IrqVector,
|
||||
},
|
||||
};
|
||||
use kernel_arch_x86::ISA_IRQ_OFFSET;
|
||||
@ -217,30 +217,15 @@ impl ExternalInterruptController for IoApic {
|
||||
|
||||
fn handle_specific_irq(&self, gsi: usize) {
|
||||
let table = self.table.read();
|
||||
let vector = IrqVector::Irq(Irq::External(gsi as u32));
|
||||
|
||||
if let Some(handler) = table.handler(gsi) {
|
||||
handler.clone().handle_irq(None);
|
||||
handler.clone().handle_irq(vector);
|
||||
} else {
|
||||
log::warn!("No handler set for GSI #{}", gsi);
|
||||
}
|
||||
}
|
||||
}
|
||||
// fn register_irq(
|
||||
// &self,
|
||||
// irq: Irq,
|
||||
// options: IrqOptions,
|
||||
// handler: &'static dyn InterruptHandler,
|
||||
// ) -> Result<(), Error> {
|
||||
// }
|
||||
//
|
||||
// fn enable_irq(&self, irq: Irq) -> Result<(), Error> {
|
||||
// }
|
||||
//
|
||||
// fn handle_specific_irq(&self, gsi: usize) {
|
||||
// let table = self.table.lock();
|
||||
//
|
||||
// }
|
||||
// }
|
||||
|
||||
impl IoApic {
|
||||
/// Creates an I/O APIC instance from its ACPI definition
|
||||
|
@ -6,17 +6,10 @@ use alloc::{sync::Arc, vec, vec::Vec};
|
||||
use device_api::{
|
||||
device::Device,
|
||||
interrupt::{
|
||||
InterruptAffinity, InterruptHandler, IpiDeliveryTarget, IpiMessage,
|
||||
InterruptAffinity, InterruptHandler, IpiDeliveryTarget, IpiMessage, IrqVector,
|
||||
LocalInterruptController, MessageInterruptController, MsiInfo,
|
||||
},
|
||||
};
|
||||
// use device_api::{
|
||||
// interrupt::{
|
||||
// InterruptAffinity, InterruptHandler, IpiDeliveryTarget, IpiMessage,
|
||||
// LocalInterruptController, MessageInterruptController, MsiInfo,
|
||||
// },
|
||||
// Device,
|
||||
// };
|
||||
use kernel_arch_x86::registers::MSR_IA32_APIC_BASE;
|
||||
use kernel_arch_x86_64::{mem::table::L3, LocalApicInterface, CPU_COUNT};
|
||||
use libk::arch::Cpu;
|
||||
@ -228,14 +221,14 @@ impl MessageInterruptController for LocalApic {
|
||||
};
|
||||
drop(table);
|
||||
|
||||
handler.handle_irq(Some(vector));
|
||||
handler.handle_irq(IrqVector::Msi(vector));
|
||||
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn register_msi_range(
|
||||
&self,
|
||||
self: Arc<Self>,
|
||||
range: &mut [MsiInfo],
|
||||
handler: Arc<dyn InterruptHandler>,
|
||||
) -> Result<(), Error> {
|
||||
|
@ -3,7 +3,7 @@ use core::{mem::size_of, ops::DerefMut, ptr::null_mut, sync::atomic::Ordering};
|
||||
|
||||
use ::acpi::{mcfg::Mcfg, AcpiTables, HpetInfo, InterruptModel};
|
||||
use abi::error::Error;
|
||||
use alloc::{boxed::Box, sync::Arc};
|
||||
use alloc::sync::Arc;
|
||||
use apic::{ioapic::IoApic, local::LocalApic};
|
||||
use device_api::device::Device;
|
||||
use kernel_arch_x86::{
|
||||
@ -251,7 +251,7 @@ impl X86_64 {
|
||||
.expect("Could not initialize memory management");
|
||||
}
|
||||
|
||||
self.init_local_cpu(cpu_id, available_features, enabled_features);
|
||||
let local_apic = self.init_local_cpu(cpu_id, available_features, enabled_features);
|
||||
|
||||
if cpu_id == 0 {
|
||||
self.setup_from_boot_data()?;
|
||||
@ -267,7 +267,7 @@ impl X86_64 {
|
||||
}
|
||||
|
||||
if let Some(acpi) = self.acpi.try_get() {
|
||||
self.init_platform_from_acpi(acpi)?;
|
||||
self.init_platform_from_acpi(acpi, local_apic)?;
|
||||
}
|
||||
|
||||
if !config::get().x86_64.disable_hpet {
|
||||
@ -322,8 +322,8 @@ impl X86_64 {
|
||||
cpu_id: usize,
|
||||
available_features: CpuFeatures,
|
||||
enabled_features: CpuFeatures,
|
||||
) {
|
||||
let local_apic = Box::new(LocalApic::new());
|
||||
) -> Arc<LocalApic> {
|
||||
let local_apic = Arc::new(LocalApic::new());
|
||||
let tss_address = gdt::init();
|
||||
exception::init_exceptions(cpu_id);
|
||||
|
||||
@ -331,7 +331,7 @@ impl X86_64 {
|
||||
this: null_mut(),
|
||||
tss_address,
|
||||
tmp_address: 0,
|
||||
local_apic,
|
||||
local_apic: local_apic.clone(),
|
||||
available_features,
|
||||
enabled_features,
|
||||
};
|
||||
@ -339,6 +339,8 @@ impl X86_64 {
|
||||
Cpu::init_local(Some(cpu_id as _), cpu_data);
|
||||
|
||||
syscall::init_syscall();
|
||||
|
||||
local_apic
|
||||
}
|
||||
|
||||
unsafe fn setup_from_boot_data(&self) -> Result<(), Error> {
|
||||
@ -364,6 +366,7 @@ impl X86_64 {
|
||||
unsafe fn init_platform_from_acpi(
|
||||
&self,
|
||||
acpi: &'static AcpiTables<AcpiHandlerImpl>,
|
||||
local_apic: Arc<LocalApic>,
|
||||
) -> Result<(), Error> {
|
||||
let platform_info = acpi.platform_info_in(AcpiAllocator).map_err(|err| {
|
||||
log::error!("Could not get ACPI platform info: {:?}", err);
|
||||
@ -392,7 +395,8 @@ impl X86_64 {
|
||||
|
||||
if let Ok(mcfg) = acpi.find_table::<Mcfg>() {
|
||||
for entry in mcfg.entries() {
|
||||
if let Err(error) = PciBusManager::add_segment_from_mcfg(entry) {
|
||||
if let Err(error) = PciBusManager::add_segment_from_mcfg(entry, local_apic.clone())
|
||||
{
|
||||
log::error!("Could not add PCI bus segment: {error:?}");
|
||||
}
|
||||
}
|
||||
|
@ -3,13 +3,17 @@
|
||||
use alloc::{collections::btree_map::BTreeMap, sync::Arc, vec::Vec};
|
||||
use device_api::{device::Device, interrupt::Irq};
|
||||
use device_tree::{
|
||||
driver::{device_tree_driver, util::pcie_interrupt_map, Node, ProbeContext},
|
||||
driver::{
|
||||
device_tree_driver,
|
||||
util::{pcie_interrupt_map, pcie_msi_map},
|
||||
Node, ProbeContext,
|
||||
},
|
||||
DeviceTreePropertyRead,
|
||||
};
|
||||
use libk_mm::address::PhysicalAddress;
|
||||
use ygg_driver_pci::{
|
||||
device::{PciInterrupt, PciInterruptPin, PciInterruptRoute},
|
||||
interrupt::PciInterruptMap,
|
||||
interrupt::{PciFixedMsiMap, PciFixedMsiMapping, PciInterruptMap, PciMsiMap},
|
||||
PciAddress, PciAddressRange, PciBusManager, PciRangeType,
|
||||
};
|
||||
|
||||
@ -78,6 +82,42 @@ fn make_interrupt_map(node: &Arc<Node>) -> Option<PciInterruptMap> {
|
||||
Some(PciInterruptMap::Fixed(imap))
|
||||
}
|
||||
|
||||
fn make_msi_map(node: &Arc<Node>) -> Option<PciMsiMap> {
|
||||
let msi_map = pcie_msi_map(node)?;
|
||||
let mut entries = Vec::new();
|
||||
|
||||
for entry in msi_map {
|
||||
let (bus, device, function) = entry.base_rid.as_parts();
|
||||
let start_address = PciAddress {
|
||||
// TODO
|
||||
segment: 0,
|
||||
bus,
|
||||
device,
|
||||
function,
|
||||
};
|
||||
let (bus, device, function) = entry.base_rid.offset(entry.length).as_parts();
|
||||
let end_address = PciAddress {
|
||||
// TODO
|
||||
segment: 0,
|
||||
bus,
|
||||
device,
|
||||
function,
|
||||
};
|
||||
|
||||
entries.push(PciFixedMsiMapping {
|
||||
start_address,
|
||||
end_address,
|
||||
controller: entry.msi_controller,
|
||||
});
|
||||
}
|
||||
|
||||
if entries.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(PciMsiMap::Fixed(PciFixedMsiMap { entries }))
|
||||
}
|
||||
}
|
||||
|
||||
device_tree_driver! {
|
||||
compatible: ["pci-host-ecam-generic"],
|
||||
driver: {
|
||||
@ -111,12 +151,18 @@ device_tree_driver! {
|
||||
}
|
||||
}
|
||||
|
||||
let msi_map = match make_msi_map(node) {
|
||||
Some(map) => map,
|
||||
None => PciMsiMap::Legacy
|
||||
};
|
||||
|
||||
PciBusManager::add_segment_from_device_tree(
|
||||
ecam_base,
|
||||
// TODO bus-range
|
||||
0..255,
|
||||
bus_ranges,
|
||||
interrupt_map
|
||||
interrupt_map,
|
||||
msi_map,
|
||||
).ok();
|
||||
|
||||
None
|
||||
|
@ -7,7 +7,7 @@ use device_api::{
|
||||
device::Device,
|
||||
interrupt::{
|
||||
ExternalInterruptController, FixedInterruptTable, FullIrq, InterruptHandler,
|
||||
InterruptTable, Irq, IrqOptions,
|
||||
InterruptTable, Irq, IrqOptions, IrqVector,
|
||||
},
|
||||
};
|
||||
use device_tree::{
|
||||
@ -175,7 +175,6 @@ impl ExternalInterruptController for Plic {
|
||||
|
||||
table.insert(irq as usize, handler)?;
|
||||
|
||||
// TODO
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -195,9 +194,10 @@ impl ExternalInterruptController for Plic {
|
||||
if irq == 0 {
|
||||
break;
|
||||
}
|
||||
let vector = IrqVector::Irq(Irq::External(irq));
|
||||
|
||||
if let Some(handler) = table.handler(irq as usize) {
|
||||
handler.clone().handle_irq(None);
|
||||
handler.clone().handle_irq(vector);
|
||||
} else {
|
||||
log::warn!("plic: no handler for IRQ #{irq}");
|
||||
}
|
||||
@ -272,6 +272,10 @@ impl DeviceTreeInterruptController for Plic {
|
||||
options: IrqOptions::default(),
|
||||
})
|
||||
}
|
||||
|
||||
fn as_interrupt_controller(self: Arc<Self>) -> Arc<dyn ExternalInterruptController> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
fn map_context_to_hart(target: u32) -> Option<u32> {
|
||||
|
@ -9,7 +9,7 @@ use abi::{
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
device::Device,
|
||||
interrupt::{FullIrq, InterruptHandler},
|
||||
interrupt::{FullIrq, InterruptHandler, IrqVector},
|
||||
};
|
||||
use device_tree::{
|
||||
driver::{device_tree_driver, lookup_phandle, Node, ProbeContext},
|
||||
@ -122,7 +122,7 @@ impl DebugSink for Bcm2835AuxUart {
|
||||
}
|
||||
|
||||
impl InterruptHandler for Bcm2835AuxUart {
|
||||
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
|
||||
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
|
||||
let inner = self.inner.get();
|
||||
|
||||
let (status, byte) = {
|
||||
|
@ -3,7 +3,7 @@ use abi::{error::Error, io::TerminalOptions};
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
device::Device,
|
||||
interrupt::{FullIrq, InterruptHandler},
|
||||
interrupt::{FullIrq, InterruptHandler, IrqVector},
|
||||
};
|
||||
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
|
||||
use libk::{
|
||||
@ -149,7 +149,7 @@ impl Device for Ns16550a {
|
||||
}
|
||||
|
||||
impl InterruptHandler for Ns16550a {
|
||||
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
|
||||
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
|
||||
let inner = self.inner.get();
|
||||
let output = inner.output();
|
||||
let byte = output.io.lock().handle_irq();
|
||||
|
@ -3,7 +3,7 @@ use abi::{error::Error, io::TerminalOptions};
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
device::Device,
|
||||
interrupt::{FullIrq, InterruptHandler},
|
||||
interrupt::{FullIrq, InterruptHandler, IrqVector},
|
||||
};
|
||||
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
|
||||
use libk::{
|
||||
@ -124,7 +124,7 @@ impl DebugSink for Pl011 {
|
||||
}
|
||||
|
||||
impl InterruptHandler for Pl011 {
|
||||
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
|
||||
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
|
||||
let inner = self.inner.get();
|
||||
let byte = inner.output().handle_irq();
|
||||
|
||||
|
@ -3,7 +3,7 @@ use abi::{error::Error, io::TerminalOptions};
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
device::Device,
|
||||
interrupt::{FullIrq, InterruptHandler},
|
||||
interrupt::{FullIrq, InterruptHandler, IrqVector},
|
||||
};
|
||||
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
|
||||
use libk::{
|
||||
@ -133,7 +133,7 @@ impl Io {
|
||||
}
|
||||
|
||||
impl InterruptHandler for DwUart {
|
||||
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
|
||||
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
|
||||
let inner = self.inner.get();
|
||||
let output = inner.output();
|
||||
let byte = output.io.lock().handle_irq();
|
||||
|
@ -39,7 +39,6 @@
|
||||
use abi::{error::Error, io::FileMode};
|
||||
use alloc::string::String;
|
||||
use arch::Platform;
|
||||
use cfg_if::cfg_if;
|
||||
use git_version::git_version;
|
||||
use kernel_arch::{Architecture, ArchitectureImpl};
|
||||
use libk::{
|
||||
@ -62,16 +61,10 @@ extern crate alloc;
|
||||
#[cfg(not(rust_analyzer))]
|
||||
extern crate compiler_builtins;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_arch = "x86_64", rust_analyzer))] {
|
||||
extern crate ygg_driver_net_rtl81xx;
|
||||
extern crate ygg_driver_usb_xhci;
|
||||
extern crate ygg_driver_nvme;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern crate ygg_driver_ahci;
|
||||
extern crate ygg_driver_net_rtl81xx;
|
||||
extern crate ygg_driver_nvme;
|
||||
extern crate ygg_driver_usb_xhci;
|
||||
extern crate ygg_driver_virtio_gpu;
|
||||
extern crate ygg_driver_virtio_net;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user