mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-09 15:26:47 +00:00
riscv
: 初始化irq (#560)
完成riscv的irqchip初始化的代码。 这是该功能的第一个PR。由于还需要实现timer驱动才能测试,因此该功能将会通过2~3个PR来完成。
This commit is contained in:
parent
bc6f0a967c
commit
338f690326
@ -26,44 +26,44 @@ kvm = []
|
|||||||
# 运行时依赖项
|
# 运行时依赖项
|
||||||
[dependencies]
|
[dependencies]
|
||||||
acpi = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/acpi-rs.git", rev = "fb69243dcf" }
|
acpi = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/acpi-rs.git", rev = "fb69243dcf" }
|
||||||
atomic_enum = "0.2.0"
|
atomic_enum = "=0.2.0"
|
||||||
bit_field = "0.10"
|
bit_field = "=0.10"
|
||||||
bitfield-struct = "0.5.3"
|
bitfield-struct = "=0.5.3"
|
||||||
bitflags = "1.3.2"
|
bitflags = "=1.3.2"
|
||||||
bitmap = { path = "crates/bitmap" }
|
bitmap = { path = "crates/bitmap" }
|
||||||
# 一个no_std的hashmap、hashset
|
# 一个no_std的hashmap、hashset
|
||||||
elf = { version = "0.7.2", default-features = false }
|
elf = { version = "=0.7.2", default-features = false }
|
||||||
hashbrown = "0.13.2"
|
hashbrown = "=0.13.2"
|
||||||
ida = { path = "src/libs/ida" }
|
ida = { path = "src/libs/ida" }
|
||||||
intertrait = { path = "src/libs/intertrait" }
|
intertrait = { path = "src/libs/intertrait" }
|
||||||
kdepends = { path = "crates/kdepends" }
|
kdepends = { path = "crates/kdepends" }
|
||||||
klog_types = { path = "crates/klog_types" }
|
klog_types = { path = "crates/klog_types" }
|
||||||
linkme = "0.2"
|
linkme = "=0.2"
|
||||||
num = { version = "0.4.0", default-features = false }
|
num = { version = "=0.4.0", default-features = false }
|
||||||
num-derive = "0.3"
|
num-derive = "=0.3"
|
||||||
num-traits = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/num-traits.git", rev="1597c1c", default-features = false }
|
num-traits = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/num-traits.git", rev="1597c1c", default-features = false }
|
||||||
raw-cpuid = "11.0.1"
|
|
||||||
smoltcp = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/smoltcp.git", rev = "9027825", default-features = false, features = ["log", "alloc", "socket-raw", "socket-udp", "socket-tcp", "socket-icmp", "socket-dhcpv4", "socket-dns", "proto-ipv4", "proto-ipv6"]}
|
smoltcp = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/smoltcp.git", rev = "9027825", default-features = false, features = ["log", "alloc", "socket-raw", "socket-udp", "socket-tcp", "socket-icmp", "socket-dhcpv4", "socket-dns", "proto-ipv4", "proto-ipv6"]}
|
||||||
system_error = { path = "crates/system_error" }
|
system_error = { path = "crates/system_error" }
|
||||||
unified-init = { path = "crates/unified-init" }
|
unified-init = { path = "crates/unified-init" }
|
||||||
virtio-drivers = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/virtio-drivers.git", rev = "f1d1cbb" }
|
virtio-drivers = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/virtio-drivers.git", rev = "f1d1cbb" }
|
||||||
fdt = "0.1.5"
|
fdt = "=0.1.5"
|
||||||
uefi = { version = "0.26.0", features = ["alloc"] }
|
uefi = { version = "=0.26.0", features = ["alloc"] }
|
||||||
uefi-raw = "0.5.0"
|
uefi-raw = "=0.5.0"
|
||||||
paste = "1.0.14"
|
paste = "=1.0.14"
|
||||||
|
|
||||||
|
|
||||||
# target为x86_64时,使用下面的依赖
|
# target为x86_64时,使用下面的依赖
|
||||||
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
||||||
mini-backtrace = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/mini-backtrace.git", rev = "e0b1d90940" }
|
mini-backtrace = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/mini-backtrace.git", rev = "e0b1d90940" }
|
||||||
x86 = "0.52.0"
|
raw-cpuid = "11.0.1"
|
||||||
x86_64 = "0.14.10"
|
x86 = "=0.52.0"
|
||||||
|
x86_64 = "=0.14.10"
|
||||||
|
|
||||||
# target为riscv64时,使用下面的依赖
|
# target为riscv64时,使用下面的依赖
|
||||||
[target.'cfg(target_arch = "riscv64")'.dependencies]
|
[target.'cfg(target_arch = "riscv64")'.dependencies]
|
||||||
riscv = { version = "0.11.0", features = [ "s-mode" ] }
|
riscv = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/riscv.git", revision = "5c01a8320e", features = [ "s-mode" ] }
|
||||||
sbi-rt = { version = "0.0.3", features = ["legacy"] }
|
sbi-rt = { version = "=0.0.3", features = ["legacy"] }
|
||||||
|
|
||||||
|
|
||||||
# 构建时依赖项
|
# 构建时依赖项
|
||||||
@ -71,7 +71,7 @@ sbi-rt = { version = "0.0.3", features = ["legacy"] }
|
|||||||
kernel_build = { path = "../build-scripts/kernel_build" }
|
kernel_build = { path = "../build-scripts/kernel_build" }
|
||||||
|
|
||||||
[dependencies.lazy_static]
|
[dependencies.lazy_static]
|
||||||
version = "1.4.0"
|
version = "=1.4.0"
|
||||||
# 由于在no_std环境,而lazy_static依赖了spin库,因此需要指定其使用no_std
|
# 由于在no_std环境,而lazy_static依赖了spin库,因此需要指定其使用no_std
|
||||||
features = ["spin_no_std"]
|
features = ["spin_no_std"]
|
||||||
|
|
||||||
|
@ -1,9 +1,22 @@
|
|||||||
use crate::smp::cpu::ProcessorId;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
init::boot_params,
|
||||||
|
kdebug,
|
||||||
|
mm::percpu::{PerCpu, PerCpuVar},
|
||||||
|
smp::cpu::{ProcessorId, SmpCpuManager},
|
||||||
|
};
|
||||||
|
|
||||||
/// 获取当前cpu的id
|
/// 获取当前cpu的id
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn current_cpu_id() -> ProcessorId {
|
pub fn current_cpu_id() -> ProcessorId {
|
||||||
unimplemented!("RiscV64 current_cpu_id")
|
let ptr: *const LocalContext = riscv::register::sscratch::read() as *const LocalContext;
|
||||||
|
|
||||||
|
if core::intrinsics::unlikely(ptr.is_null()) {
|
||||||
|
return boot_params().read_irqsave().arch.boot_hartid;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe { (*ptr).current_cpu() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 重置cpu
|
/// 重置cpu
|
||||||
@ -11,3 +24,64 @@ pub unsafe fn cpu_reset() -> ! {
|
|||||||
sbi_rt::system_reset(sbi_rt::WarmReboot, sbi_rt::NoReason);
|
sbi_rt::system_reset(sbi_rt::WarmReboot, sbi_rt::NoReason);
|
||||||
unimplemented!("RiscV64 reset failed, manual override expected ...")
|
unimplemented!("RiscV64 reset failed, manual override expected ...")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static mut LOCAL_CONTEXT: Option<PerCpuVar<LocalContext>> = None;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(super) fn local_context() -> &'static PerCpuVar<LocalContext> {
|
||||||
|
unsafe { LOCAL_CONTEXT.as_ref().unwrap() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Per cpu的上下文数据
|
||||||
|
///
|
||||||
|
/// 每个CPU的sscratch寄存器指向这个结构体
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(super) struct LocalContext {
|
||||||
|
/// 当前cpu的id
|
||||||
|
current_cpu: ProcessorId,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LocalContext {
|
||||||
|
fn new(cpu: ProcessorId) -> Self {
|
||||||
|
Self { current_cpu: cpu }
|
||||||
|
}
|
||||||
|
pub fn current_cpu(&self) -> ProcessorId {
|
||||||
|
self.current_cpu
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_current_cpu(&mut self, cpu: ProcessorId) {
|
||||||
|
self.current_cpu = cpu;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sync_to_cpu(&self) {
|
||||||
|
let ptr = self as *const Self as usize;
|
||||||
|
riscv::register::sscratch::write(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 初始化本地上下文
|
||||||
|
#[inline(never)]
|
||||||
|
pub(super) fn init_local_context() {
|
||||||
|
kdebug!("init_local_context");
|
||||||
|
let mut data = Vec::new();
|
||||||
|
|
||||||
|
for i in 0..PerCpu::MAX_CPU_NUM {
|
||||||
|
data.push(LocalContext::new(ProcessorId::new(i)));
|
||||||
|
}
|
||||||
|
let ctx = PerCpuVar::new(data).unwrap();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
LOCAL_CONTEXT = Some(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
let hartid = boot_params().read().arch.boot_hartid;
|
||||||
|
|
||||||
|
let ctx = unsafe { local_context().force_get(hartid) };
|
||||||
|
ctx.sync_to_cpu();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SmpCpuManager {
|
||||||
|
pub fn arch_init(boot_cpu: ProcessorId) {
|
||||||
|
// todo: 读取所有可用的CPU
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -3,26 +3,33 @@ use system_error::SystemError;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{driver::sbi::SbiDriver, mm::init::mm_early_init},
|
arch::{driver::sbi::SbiDriver, mm::init::mm_early_init},
|
||||||
driver::{firmware::efi::init::efi_init, open_firmware::fdt::open_firmware_fdt_driver},
|
driver::{
|
||||||
|
firmware::efi::init::efi_init, irqchip::riscv_intc::riscv_intc_init,
|
||||||
|
open_firmware::fdt::open_firmware_fdt_driver,
|
||||||
|
},
|
||||||
init::{boot_params, init::start_kernel},
|
init::{boot_params, init::start_kernel},
|
||||||
kdebug, kinfo,
|
kdebug, kinfo,
|
||||||
mm::{memblock::mem_block_manager, PhysAddr, VirtAddr},
|
mm::{memblock::mem_block_manager, PhysAddr, VirtAddr},
|
||||||
print, println,
|
print, println,
|
||||||
|
smp::cpu::ProcessorId,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::driver::sbi::console_putstr;
|
use super::{cpu::init_local_context, driver::sbi::console_putstr};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ArchBootParams {
|
pub struct ArchBootParams {
|
||||||
/// 启动时的fdt物理地址
|
/// 启动时的fdt物理地址
|
||||||
pub fdt_paddr: PhysAddr,
|
pub fdt_paddr: PhysAddr,
|
||||||
pub fdt_vaddr: Option<VirtAddr>,
|
pub fdt_vaddr: Option<VirtAddr>,
|
||||||
|
|
||||||
|
pub boot_hartid: ProcessorId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ArchBootParams {
|
impl ArchBootParams {
|
||||||
pub const DEFAULT: Self = ArchBootParams {
|
pub const DEFAULT: Self = ArchBootParams {
|
||||||
fdt_paddr: PhysAddr::new(0),
|
fdt_paddr: PhysAddr::new(0),
|
||||||
fdt_vaddr: None,
|
fdt_vaddr: None,
|
||||||
|
boot_hartid: ProcessorId::new(0),
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn arch_fdt(&self) -> VirtAddr {
|
pub fn arch_fdt(&self) -> VirtAddr {
|
||||||
@ -34,7 +41,7 @@ impl ArchBootParams {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static mut BOOT_HARTID: usize = 0;
|
static mut BOOT_HARTID: u32 = 0;
|
||||||
static mut BOOT_FDT_PADDR: PhysAddr = PhysAddr::new(0);
|
static mut BOOT_FDT_PADDR: PhysAddr = PhysAddr::new(0);
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@ -42,7 +49,7 @@ unsafe extern "C" fn kernel_main(hartid: usize, fdt_paddr: usize) -> ! {
|
|||||||
let fdt_paddr = PhysAddr::new(fdt_paddr);
|
let fdt_paddr = PhysAddr::new(fdt_paddr);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
BOOT_HARTID = hartid;
|
BOOT_HARTID = hartid as u32;
|
||||||
BOOT_FDT_PADDR = fdt_paddr;
|
BOOT_FDT_PADDR = fdt_paddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,9 +86,14 @@ unsafe fn parse_dtb() {
|
|||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
pub fn early_setup_arch() -> Result<(), SystemError> {
|
pub fn early_setup_arch() -> Result<(), SystemError> {
|
||||||
SbiDriver::early_init();
|
SbiDriver::early_init();
|
||||||
let hartid: usize = unsafe { BOOT_HARTID };
|
let hartid = unsafe { BOOT_HARTID };
|
||||||
let fdt_paddr = unsafe { BOOT_FDT_PADDR };
|
let fdt_paddr = unsafe { BOOT_FDT_PADDR };
|
||||||
boot_params().write().arch.fdt_paddr = fdt_paddr;
|
|
||||||
|
let mut arch_boot_params_guard = boot_params().write();
|
||||||
|
arch_boot_params_guard.arch.fdt_paddr = fdt_paddr;
|
||||||
|
arch_boot_params_guard.arch.boot_hartid = ProcessorId::new(hartid);
|
||||||
|
|
||||||
|
drop(arch_boot_params_guard);
|
||||||
|
|
||||||
kinfo!(
|
kinfo!(
|
||||||
"DragonOS kernel is running on hart {}, fdt address:{:?}",
|
"DragonOS kernel is running on hart {}, fdt address:{:?}",
|
||||||
@ -109,7 +121,7 @@ pub fn early_setup_arch() -> Result<(), SystemError> {
|
|||||||
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
pub fn setup_arch() -> Result<(), SystemError> {
|
pub fn setup_arch() -> Result<(), SystemError> {
|
||||||
// todo
|
init_local_context();
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
use system_error::SystemError;
|
use system_error::SystemError;
|
||||||
|
|
||||||
use crate::exception::{InterruptArch, IrqFlags, IrqFlagsGuard, IrqNumber};
|
use crate::{
|
||||||
|
driver::irqchip::riscv_intc::riscv_intc_init,
|
||||||
|
exception::{InterruptArch, IrqFlags, IrqFlagsGuard, IrqNumber},
|
||||||
|
};
|
||||||
|
|
||||||
pub mod ipi;
|
pub mod ipi;
|
||||||
|
|
||||||
@ -8,7 +11,9 @@ pub struct RiscV64InterruptArch;
|
|||||||
|
|
||||||
impl InterruptArch for RiscV64InterruptArch {
|
impl InterruptArch for RiscV64InterruptArch {
|
||||||
unsafe fn arch_irq_init() -> Result<(), SystemError> {
|
unsafe fn arch_irq_init() -> Result<(), SystemError> {
|
||||||
todo!("RiscV64InterruptArch::arch_irq_init")
|
riscv_intc_init()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
unsafe fn interrupt_enable() {
|
unsafe fn interrupt_enable() {
|
||||||
riscv::interrupt::enable();
|
riscv::interrupt::enable();
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use x86::cpuid::{cpuid, CpuIdResult};
|
use x86::cpuid::{cpuid, CpuIdResult};
|
||||||
|
|
||||||
use crate::smp::cpu::ProcessorId;
|
use crate::smp::cpu::{ProcessorId, SmpCpuManager};
|
||||||
|
|
||||||
/// 获取当前cpu的apic id
|
/// 获取当前cpu的apic id
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -16,3 +16,7 @@ pub unsafe fn cpu_reset() -> ! {
|
|||||||
unsafe { x86::io::outb(0x64, 0xfe) };
|
unsafe { x86::io::outb(0x64, 0xfe) };
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SmpCpuManager {
|
||||||
|
pub fn arch_init(_boot_cpu: ProcessorId) {}
|
||||||
|
}
|
||||||
|
@ -23,12 +23,5 @@ pub fn driver_init() -> Result<(), SystemError> {
|
|||||||
cpu_device_manager().init()?;
|
cpu_device_manager().init()?;
|
||||||
|
|
||||||
// 至此,已完成设备驱动模型的初始化
|
// 至此,已完成设备驱动模型的初始化
|
||||||
// 接下来,初始化设备
|
|
||||||
actual_device_init()?;
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn actual_device_init() -> Result<(), SystemError> {
|
|
||||||
// 应当使用unified_init来初始化
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
2
kernel/src/driver/irqchip/mod.rs
Normal file
2
kernel/src/driver/irqchip/mod.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
pub mod riscv_intc;
|
134
kernel/src/driver/irqchip/riscv_intc.rs
Normal file
134
kernel/src/driver/irqchip/riscv_intc.rs
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
use alloc::{string::ToString, sync::Arc};
|
||||||
|
use system_error::SystemError;
|
||||||
|
|
||||||
|
use crate::exception::{
|
||||||
|
handle::PerCpuDevIdIrqHandler,
|
||||||
|
irqchip::{IrqChip, IrqChipFlags},
|
||||||
|
irqdata::IrqData,
|
||||||
|
irqdesc::irq_desc_manager,
|
||||||
|
irqdomain::{irq_domain_manager, IrqDomain, IrqDomainOps},
|
||||||
|
HardwareIrqNumber, IrqNumber,
|
||||||
|
};
|
||||||
|
|
||||||
|
static mut RISCV_INTC_DOMAIN: Option<Arc<IrqDomain>> = None;
|
||||||
|
static mut RISCV_INTC_CHIP: Option<Arc<RiscvIntcChip>> = None;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn riscv_intc_domain() -> &'static Option<Arc<IrqDomain>> {
|
||||||
|
unsafe { &RISCV_INTC_DOMAIN }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn riscv_intc_chip() -> Option<&'static Arc<RiscvIntcChip>> {
|
||||||
|
unsafe { RISCV_INTC_CHIP.as_ref() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct RiscvIntcChip;
|
||||||
|
|
||||||
|
impl IrqChip for RiscvIntcChip {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"RISC-V INTC"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn irq_disable(&self, _irq: &Arc<IrqData>) {}
|
||||||
|
|
||||||
|
fn irq_mask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||||
|
unsafe { riscv::register::sie::clear_bits(1 << irq.hardware_irq().data()) };
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn irq_unmask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||||
|
unsafe { riscv::register::sie::set_bits(1 << irq.hardware_irq().data()) };
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn irq_ack(&self, irq: &Arc<IrqData>) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_mask_ack(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn irq_eoi(&self, _irq: &Arc<IrqData>) {
|
||||||
|
/*
|
||||||
|
* The RISC-V INTC driver uses handle_percpu_devid_irq() flow
|
||||||
|
* for the per-HART local interrupts and child irqchip drivers
|
||||||
|
* (such as PLIC, SBI IPI, CLINT, APLIC, IMSIC, etc) implement
|
||||||
|
* chained handlers for the per-HART local interrupts.
|
||||||
|
*
|
||||||
|
* In the absence of irq_eoi(), the chained_irq_enter() and
|
||||||
|
* chained_irq_exit() functions (used by child irqchip drivers)
|
||||||
|
* will do unnecessary mask/unmask of per-HART local interrupts
|
||||||
|
* at the time of handling interrupts. To avoid this, we provide
|
||||||
|
* an empty irq_eoi() callback for RISC-V INTC irqchip.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_set_affinity(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_set_flow_type(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flags(&self) -> IrqChipFlags {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct RiscvIntcDomainOps;
|
||||||
|
|
||||||
|
impl IrqDomainOps for RiscvIntcDomainOps {
|
||||||
|
fn map(
|
||||||
|
&self,
|
||||||
|
irq_domain: &Arc<IrqDomain>,
|
||||||
|
hwirq: HardwareIrqNumber,
|
||||||
|
virq: IrqNumber,
|
||||||
|
) -> Result<(), SystemError> {
|
||||||
|
irq_desc_manager().set_percpu_devid_all(virq)?;
|
||||||
|
irq_domain_manager().domain_set_info(
|
||||||
|
irq_domain,
|
||||||
|
virq,
|
||||||
|
hwirq,
|
||||||
|
riscv_intc_chip().unwrap().clone() as Arc<dyn IrqChip>,
|
||||||
|
irq_domain.host_data(),
|
||||||
|
&PerCpuDevIdIrqHandler,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unmap(&self, irq_domain: &Arc<IrqDomain>, virq: IrqNumber) {
|
||||||
|
todo!("riscv_intc_domain_ops::unmap");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
pub unsafe fn riscv_intc_init() -> Result<(), SystemError> {
|
||||||
|
let intc_chip = Arc::new(RiscvIntcChip);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
RISCV_INTC_CHIP = Some(intc_chip);
|
||||||
|
}
|
||||||
|
|
||||||
|
let intc_domain = irq_domain_manager()
|
||||||
|
.create_and_add_linear("riscv-intc".to_string(), &RiscvIntcDomainOps, 64)
|
||||||
|
.ok_or_else(|| {
|
||||||
|
kerror!("Failed to create riscv-intc domain");
|
||||||
|
SystemError::ENXIO
|
||||||
|
})?;
|
||||||
|
|
||||||
|
irq_domain_manager().set_default_domain(intc_domain.clone());
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
RISCV_INTC_DOMAIN = Some(intc_domain);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
@ -3,6 +3,7 @@ pub mod base;
|
|||||||
pub mod disk;
|
pub mod disk;
|
||||||
pub mod firmware;
|
pub mod firmware;
|
||||||
pub mod input;
|
pub mod input;
|
||||||
|
pub mod irqchip;
|
||||||
pub mod keyboard;
|
pub mod keyboard;
|
||||||
pub mod net;
|
pub mod net;
|
||||||
pub mod open_firmware;
|
pub mod open_firmware;
|
||||||
|
@ -6,8 +6,9 @@ use system_error::SystemError;
|
|||||||
use crate::{
|
use crate::{
|
||||||
arch::{interrupt::TrapFrame, CurrentIrqArch},
|
arch::{interrupt::TrapFrame, CurrentIrqArch},
|
||||||
exception::irqdesc::InnerIrqDesc,
|
exception::irqdesc::InnerIrqDesc,
|
||||||
libs::spinlock::SpinLockGuard,
|
libs::{once::Once, spinlock::SpinLockGuard},
|
||||||
process::{ProcessFlags, ProcessManager},
|
process::{ProcessFlags, ProcessManager},
|
||||||
|
smp::core::smp_get_processor_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
@ -148,7 +149,7 @@ fn irq_may_run(desc_inner_guard: &SpinLockGuard<'_, InnerIrqDesc>) -> bool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mask_ack_irq(irq_data: &Arc<IrqData>) {
|
pub(super) fn mask_ack_irq(irq_data: &Arc<IrqData>) {
|
||||||
let chip = irq_data.chip_info_read_irqsave().chip();
|
let chip = irq_data.chip_info_read_irqsave().chip();
|
||||||
if chip.can_mask_ack() {
|
if chip.can_mask_ack() {
|
||||||
chip.irq_mask_ack(&irq_data);
|
chip.irq_mask_ack(&irq_data);
|
||||||
@ -242,3 +243,71 @@ fn warn_no_thread(irq: IrqNumber, action_inner: &mut SpinLockGuard<'_, InnerIrqA
|
|||||||
action_inner.name()
|
action_inner.name()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `handle_percpu_devid_irq` - 带有per-CPU设备id的perCPU本地中断处理程序
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// * `desc`: 此中断的中断描述结构
|
||||||
|
///
|
||||||
|
/// 在没有锁定要求的SMP机器上的每个CPU中断。与linux的`handle_percpu_irq()`相同,但有以下额外内容:
|
||||||
|
///
|
||||||
|
/// `action->percpu_dev_id`是一个指向per-cpu变量的指针,这些变量
|
||||||
|
/// 包含调用此处理程序的cpu的真实设备id
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PerCpuDevIdIrqHandler;
|
||||||
|
|
||||||
|
impl IrqFlowHandler for PerCpuDevIdIrqHandler {
|
||||||
|
fn handle(&self, irq_desc: &Arc<IrqDesc>, _trap_frame: &mut TrapFrame) {
|
||||||
|
let desc_inner_guard = irq_desc.inner();
|
||||||
|
let irq_data = desc_inner_guard.irq_data().clone();
|
||||||
|
let chip = irq_data.chip_info_read().chip();
|
||||||
|
|
||||||
|
chip.irq_ack(&irq_data);
|
||||||
|
|
||||||
|
let irq = irq_data.irq();
|
||||||
|
|
||||||
|
let action = desc_inner_guard.actions().first().cloned();
|
||||||
|
|
||||||
|
drop(desc_inner_guard);
|
||||||
|
|
||||||
|
if let Some(action) = action {
|
||||||
|
let action_inner = action.inner();
|
||||||
|
let per_cpu_devid = action_inner.per_cpu_dev_id().cloned();
|
||||||
|
|
||||||
|
let handler = action_inner.handler().unwrap();
|
||||||
|
drop(action_inner);
|
||||||
|
|
||||||
|
let _r = handler.handle(
|
||||||
|
irq,
|
||||||
|
None,
|
||||||
|
per_cpu_devid.map(|d| d as Arc<dyn IrqHandlerData>),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let cpu = smp_get_processor_id();
|
||||||
|
|
||||||
|
let enabled = irq_desc
|
||||||
|
.inner()
|
||||||
|
.percpu_enabled()
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.get(cpu)
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
if enabled {
|
||||||
|
irq_manager().irq_percpu_disable(irq_desc, &irq_data, &chip, cpu);
|
||||||
|
}
|
||||||
|
static ONCE: Once = Once::new();
|
||||||
|
|
||||||
|
ONCE.call_once(|| {
|
||||||
|
kerror!(
|
||||||
|
"Spurious percpu irq {} on cpu {:?}, enabled: {}",
|
||||||
|
irq.data(),
|
||||||
|
cpu,
|
||||||
|
enabled
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
chip.irq_eoi(&irq_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,21 +1,36 @@
|
|||||||
use core::{any::Any, fmt::Debug};
|
use core::{any::Any, fmt::Debug, intrinsics::unlikely};
|
||||||
|
|
||||||
use alloc::{
|
use alloc::{
|
||||||
|
string::{String, ToString},
|
||||||
sync::{Arc, Weak},
|
sync::{Arc, Weak},
|
||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
use system_error::SystemError;
|
use system_error::SystemError;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
libs::{cpumask::CpuMask, spinlock::SpinLock},
|
exception::{
|
||||||
|
dummychip::no_irq_chip,
|
||||||
|
handle::{bad_irq_handler, mask_ack_irq},
|
||||||
|
irqdata::IrqStatus,
|
||||||
|
irqdesc::irq_desc_manager,
|
||||||
|
manage::irq_manager,
|
||||||
|
},
|
||||||
|
libs::{
|
||||||
|
cpumask::CpuMask,
|
||||||
|
once::Once,
|
||||||
|
spinlock::{SpinLock, SpinLockGuard},
|
||||||
|
},
|
||||||
mm::VirtAddr,
|
mm::VirtAddr,
|
||||||
|
smp::cpu::ProcessorId,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
irqdata::{IrqData, IrqLineStatus},
|
irqdata::{IrqData, IrqHandlerData, IrqLineStatus},
|
||||||
|
irqdesc::{InnerIrqDesc, IrqAction, IrqDesc, IrqFlowHandler, IrqHandler, IrqReturn},
|
||||||
irqdomain::IrqDomain,
|
irqdomain::IrqDomain,
|
||||||
manage::IrqManager,
|
manage::IrqManager,
|
||||||
msi::MsiMsg,
|
msi::MsiMsg,
|
||||||
|
IrqNumber,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#506
|
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#506
|
||||||
@ -48,7 +63,7 @@ pub trait IrqChip: Sync + Send + Any + Debug {
|
|||||||
///
|
///
|
||||||
/// 用于屏蔽中断
|
/// 用于屏蔽中断
|
||||||
///
|
///
|
||||||
/// 如果返回ENOSYS,则表明irq_mask()不支持.
|
/// 如果返回ENOSYS,则表明irq_mask()不支持. 那么中断机制代码将调用irq_disable()。
|
||||||
///
|
///
|
||||||
/// 如果返回错误,那么中断的屏蔽状态将不会改变。
|
/// 如果返回错误,那么中断的屏蔽状态将不会改变。
|
||||||
fn irq_mask(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
fn irq_mask(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||||
@ -367,4 +382,203 @@ impl IrqManager {
|
|||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn __irq_set_handler(
|
||||||
|
&self,
|
||||||
|
irq: IrqNumber,
|
||||||
|
handler: &'static dyn IrqFlowHandler,
|
||||||
|
is_chained: bool,
|
||||||
|
name: Option<String>,
|
||||||
|
) {
|
||||||
|
let r = irq_desc_manager().lookup_and_lock_bus(irq, false, false);
|
||||||
|
if r.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let irq_desc = r.unwrap();
|
||||||
|
|
||||||
|
let mut desc_inner = irq_desc.inner();
|
||||||
|
self.__irq_do_set_handler(&irq_desc, &mut desc_inner, Some(handler), is_chained, name);
|
||||||
|
|
||||||
|
drop(desc_inner);
|
||||||
|
irq_desc.chip_bus_sync_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn __irq_do_set_handler(
|
||||||
|
&self,
|
||||||
|
desc: &Arc<IrqDesc>,
|
||||||
|
desc_inner: &mut SpinLockGuard<'_, InnerIrqDesc>,
|
||||||
|
mut handler: Option<&'static dyn IrqFlowHandler>,
|
||||||
|
is_chained: bool,
|
||||||
|
name: Option<String>,
|
||||||
|
) {
|
||||||
|
if handler.is_none() {
|
||||||
|
handler = Some(bad_irq_handler());
|
||||||
|
} else {
|
||||||
|
let mut irq_data = Some(desc_inner.irq_data().clone());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 在具有中断域继承的domain中,我们可能会遇到这样的情况,
|
||||||
|
* 最外层的芯片还没有设置好,但是内部的芯片已经存在了。
|
||||||
|
* 我们选择安装处理程序,而不是退出,
|
||||||
|
* 但显然我们此时无法启用/启动中断。
|
||||||
|
*/
|
||||||
|
while irq_data.is_some() {
|
||||||
|
let dt = irq_data.as_ref().unwrap().clone();
|
||||||
|
|
||||||
|
let chip_info = dt.chip_info_read_irqsave();
|
||||||
|
|
||||||
|
if !Arc::ptr_eq(&chip_info.chip(), &no_irq_chip()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 如果最外层的芯片没有设置好,并且预期立即开始中断,
|
||||||
|
* 则放弃。
|
||||||
|
*/
|
||||||
|
if unlikely(is_chained) {
|
||||||
|
kwarn!(
|
||||||
|
"Chained handler for irq {} is not supported",
|
||||||
|
dt.irq().data()
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// try the parent
|
||||||
|
let parent_data = dt.parent_data().map(|p| p.upgrade()).flatten();
|
||||||
|
|
||||||
|
irq_data = parent_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if unlikely(
|
||||||
|
irq_data.is_none()
|
||||||
|
|| Arc::ptr_eq(
|
||||||
|
&irq_data.as_ref().unwrap().chip_info_read_irqsave().chip(),
|
||||||
|
&no_irq_chip(),
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
kwarn!("No irq chip for irq {}", desc_inner.irq_data().irq().data());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let handler = handler.unwrap();
|
||||||
|
if core::ptr::eq(handler, bad_irq_handler()) {
|
||||||
|
if Arc::ptr_eq(
|
||||||
|
&desc_inner.irq_data().chip_info_read_irqsave().chip(),
|
||||||
|
&no_irq_chip(),
|
||||||
|
) {
|
||||||
|
let irq_data = desc_inner.irq_data();
|
||||||
|
mask_ack_irq(irq_data);
|
||||||
|
|
||||||
|
irq_data.irqd_set(IrqStatus::IRQD_IRQ_DISABLED);
|
||||||
|
|
||||||
|
if is_chained {
|
||||||
|
desc_inner.clear_actions();
|
||||||
|
}
|
||||||
|
desc_inner.set_depth(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let chip = desc_inner.irq_data().chip_info_read_irqsave().chip();
|
||||||
|
desc.set_handler_no_lock_inner(handler, desc_inner.irq_data(), &chip);
|
||||||
|
desc_inner.set_name(name);
|
||||||
|
|
||||||
|
if !core::ptr::eq(handler, bad_irq_handler()) && is_chained {
|
||||||
|
let trigger_type = desc_inner.common_data().trigger_type();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 我们即将立即启动这个中断,
|
||||||
|
* 因此需要设置触发配置。
|
||||||
|
* 但是 .irq_set_type 回调可能已经覆盖了
|
||||||
|
* irqflowhandler,忽略了我们正在处理的
|
||||||
|
* 是一个链式中断。立即重置它,因为我们
|
||||||
|
* 确实知道更好的处理方式。
|
||||||
|
*/
|
||||||
|
|
||||||
|
if trigger_type != IrqLineStatus::IRQ_TYPE_NONE {
|
||||||
|
irq_manager()
|
||||||
|
.do_set_irq_trigger(desc.clone(), desc_inner, trigger_type)
|
||||||
|
.ok();
|
||||||
|
desc.set_handler(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
desc_inner.set_noprobe();
|
||||||
|
desc_inner.set_norequest();
|
||||||
|
desc_inner.set_nothread();
|
||||||
|
|
||||||
|
desc_inner.clear_actions();
|
||||||
|
desc_inner.add_action(chained_action());
|
||||||
|
|
||||||
|
irq_manager()
|
||||||
|
.irq_activate_and_startup(desc, desc_inner, IrqManager::IRQ_RESEND)
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn irq_set_handler_data(
|
||||||
|
&self,
|
||||||
|
irq: IrqNumber,
|
||||||
|
data: Option<Arc<dyn IrqHandlerData>>,
|
||||||
|
) -> Result<(), SystemError> {
|
||||||
|
let desc = irq_desc_manager().lookup(irq).ok_or(SystemError::EINVAL)?;
|
||||||
|
desc.inner().common_data().inner().set_handler_data(data);
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn irq_percpu_disable(
|
||||||
|
&self,
|
||||||
|
desc: &Arc<IrqDesc>,
|
||||||
|
irq_data: &Arc<IrqData>,
|
||||||
|
irq_chip: &Arc<dyn IrqChip>,
|
||||||
|
cpu: ProcessorId,
|
||||||
|
) {
|
||||||
|
if let Err(e) = irq_chip.irq_mask(irq_data) {
|
||||||
|
if e == SystemError::ENOSYS {
|
||||||
|
irq_chip.irq_disable(irq_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
desc.inner()
|
||||||
|
.percpu_enabled_mut()
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.set(cpu, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub(super) static ref CHAINED_ACTION: Arc<IrqAction> = IrqAction::new(
|
||||||
|
IrqNumber::new(0),
|
||||||
|
"".to_string(),
|
||||||
|
Some(&ChainedActionHandler),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(super) fn chained_action() -> Arc<IrqAction> {
|
||||||
|
CHAINED_ACTION.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Chained handlers 永远不应该在它们的IRQ上调用irqaction。如果发生这种情况,
|
||||||
|
/// 这个默认irqaction将发出警告。
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct ChainedActionHandler;
|
||||||
|
|
||||||
|
impl IrqHandler for ChainedActionHandler {
|
||||||
|
fn handle(
|
||||||
|
&self,
|
||||||
|
irq: IrqNumber,
|
||||||
|
_static_data: Option<&dyn IrqHandlerData>,
|
||||||
|
_dynamic_data: Option<Arc<dyn IrqHandlerData>>,
|
||||||
|
) -> Result<IrqReturn, SystemError> {
|
||||||
|
static ONCE: Once = Once::new();
|
||||||
|
ONCE.call_once(|| {
|
||||||
|
kwarn!("Chained irq {} should not call an action.", irq.data());
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(IrqReturn::NotHandled)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -288,11 +288,15 @@ impl IrqCommonData {
|
|||||||
pub fn set_affinity(&self, affinity: CpuMask) {
|
pub fn set_affinity(&self, affinity: CpuMask) {
|
||||||
self.inner.lock_irqsave().affinity = affinity;
|
self.inner.lock_irqsave().affinity = affinity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn inner(&self) -> SpinLockGuard<InnerIrqCommonData> {
|
||||||
|
self.inner.lock_irqsave()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct InnerIrqCommonData {
|
pub struct InnerIrqCommonData {
|
||||||
/// status information for irq chip functions.
|
/// status information for irq chip functions.
|
||||||
state: IrqStatus,
|
state: IrqStatus,
|
||||||
/// per-IRQ data for the irq_chip methods
|
/// per-IRQ data for the irq_chip methods
|
||||||
@ -309,6 +313,16 @@ impl InnerIrqCommonData {
|
|||||||
pub fn irqd_clear(&mut self, status: IrqStatus) {
|
pub fn irqd_clear(&mut self, status: IrqStatus) {
|
||||||
self.state.remove(status);
|
self.state.remove(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn set_handler_data(&mut self, handler_data: Option<Arc<dyn IrqHandlerData>>) {
|
||||||
|
self.handler_data = handler_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn handler_data(&self) -> Option<Arc<dyn IrqHandlerData>> {
|
||||||
|
self.handler_data.clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 中断处理函数传入的数据
|
/// 中断处理函数传入的数据
|
||||||
@ -400,6 +414,11 @@ impl IrqLineStatus {
|
|||||||
}
|
}
|
||||||
return Some(self.contains(Self::IRQ_TYPE_LEVEL_HIGH));
|
return Some(self.contains(Self::IRQ_TYPE_LEVEL_HIGH));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn is_per_cpu_devid(&self) -> bool {
|
||||||
|
self.contains(Self::IRQ_PER_CPU_DEVID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
bitflags! {
|
bitflags! {
|
||||||
/// 中断状态(存储在IrqCommonData)
|
/// 中断状态(存储在IrqCommonData)
|
||||||
|
@ -21,17 +21,21 @@ use crate::{
|
|||||||
},
|
},
|
||||||
filesystem::kernfs::KernFSInode,
|
filesystem::kernfs::KernFSInode,
|
||||||
libs::{
|
libs::{
|
||||||
|
cpumask::CpuMask,
|
||||||
mutex::{Mutex, MutexGuard},
|
mutex::{Mutex, MutexGuard},
|
||||||
rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard},
|
rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||||
spinlock::{SpinLock, SpinLockGuard},
|
spinlock::{SpinLock, SpinLockGuard},
|
||||||
},
|
},
|
||||||
|
mm::percpu::PerCpuVar,
|
||||||
process::ProcessControlBlock,
|
process::ProcessControlBlock,
|
||||||
sched::completion::Completion,
|
sched::completion::Completion,
|
||||||
|
smp::cpu::smp_cpu_manager,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
dummychip::no_irq_chip,
|
dummychip::no_irq_chip,
|
||||||
handle::bad_irq_handler,
|
handle::bad_irq_handler,
|
||||||
|
irqchip::IrqChip,
|
||||||
irqdata::{IrqCommonData, IrqData, IrqHandlerData, IrqLineStatus, IrqStatus},
|
irqdata::{IrqCommonData, IrqData, IrqHandlerData, IrqLineStatus, IrqStatus},
|
||||||
sysfs::{irq_sysfs_del, IrqKObjType},
|
sysfs::{irq_sysfs_del, IrqKObjType},
|
||||||
HardwareIrqNumber, InterruptArch, IrqNumber,
|
HardwareIrqNumber, InterruptArch, IrqNumber,
|
||||||
@ -95,6 +99,8 @@ impl IrqDesc {
|
|||||||
|
|
||||||
let irq_desc = IrqDesc {
|
let irq_desc = IrqDesc {
|
||||||
inner: SpinLock::new(InnerIrqDesc {
|
inner: SpinLock::new(InnerIrqDesc {
|
||||||
|
percpu_affinity: None,
|
||||||
|
percpu_enabled: None,
|
||||||
common_data,
|
common_data,
|
||||||
irq_data,
|
irq_data,
|
||||||
desc_internal_state: IrqDescState::empty(),
|
desc_internal_state: IrqDescState::empty(),
|
||||||
@ -144,6 +150,24 @@ impl IrqDesc {
|
|||||||
self.chip_bus_sync_unlock();
|
self.chip_bus_sync_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 设置中断处理程序(不对desc->inner)
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// ## Safety
|
||||||
|
///
|
||||||
|
/// 需要保证irq_data和chip是当前irqdesc的
|
||||||
|
pub fn set_handler_no_lock_inner(
|
||||||
|
&self,
|
||||||
|
handler: &'static dyn IrqFlowHandler,
|
||||||
|
irq_data: &Arc<IrqData>,
|
||||||
|
chip: &Arc<dyn IrqChip>,
|
||||||
|
) {
|
||||||
|
chip.irq_bus_lock(irq_data).ok();
|
||||||
|
let mut guard = self.handler.write_irqsave();
|
||||||
|
*guard = Some(handler);
|
||||||
|
chip.irq_bus_sync_unlock(irq_data).ok();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn handler(&self) -> Option<&'static dyn IrqFlowHandler> {
|
pub fn handler(&self) -> Option<&'static dyn IrqFlowHandler> {
|
||||||
let guard = self.handler.read_irqsave();
|
let guard = self.handler.read_irqsave();
|
||||||
*guard
|
*guard
|
||||||
@ -248,6 +272,17 @@ impl IrqDesc {
|
|||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_percpu_devid_flags(&self) {
|
||||||
|
self.modify_status(
|
||||||
|
IrqLineStatus::empty(),
|
||||||
|
IrqLineStatus::IRQ_NOAUTOEN
|
||||||
|
| IrqLineStatus::IRQ_PER_CPU
|
||||||
|
| IrqLineStatus::IRQ_NOTHREAD
|
||||||
|
| IrqLineStatus::IRQ_NOPROBE
|
||||||
|
| IrqLineStatus::IRQ_PER_CPU_DEVID,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn modify_status(&self, clear: IrqLineStatus, set: IrqLineStatus) {
|
pub fn modify_status(&self, clear: IrqLineStatus, set: IrqLineStatus) {
|
||||||
let mut desc_guard = self.inner();
|
let mut desc_guard = self.inner();
|
||||||
desc_guard.line_status.remove(clear);
|
desc_guard.line_status.remove(clear);
|
||||||
@ -323,6 +358,10 @@ pub struct InnerIrqDesc {
|
|||||||
kern_inode: Option<Arc<KernFSInode>>,
|
kern_inode: Option<Arc<KernFSInode>>,
|
||||||
kset: Option<Arc<KSet>>,
|
kset: Option<Arc<KSet>>,
|
||||||
parent_kobj: Option<Weak<dyn KObject>>,
|
parent_kobj: Option<Weak<dyn KObject>>,
|
||||||
|
/// per-cpu enabled mask
|
||||||
|
percpu_enabled: Option<CpuMask>,
|
||||||
|
/// per-cpu affinity
|
||||||
|
percpu_affinity: Option<CpuMask>,
|
||||||
// wait_for_threads: EventWaitQueue
|
// wait_for_threads: EventWaitQueue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,6 +370,11 @@ impl InnerIrqDesc {
|
|||||||
self.name.as_ref()
|
self.name.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn set_name(&mut self, name: Option<String>) {
|
||||||
|
self.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn can_request(&self) -> bool {
|
pub fn can_request(&self) -> bool {
|
||||||
!self.line_status.contains(IrqLineStatus::IRQ_NOREQUEST)
|
!self.line_status.contains(IrqLineStatus::IRQ_NOREQUEST)
|
||||||
}
|
}
|
||||||
@ -345,6 +389,24 @@ impl InnerIrqDesc {
|
|||||||
self.line_status.remove(IrqLineStatus::IRQ_NOREQUEST);
|
self.line_status.remove(IrqLineStatus::IRQ_NOREQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn set_noprobe(&mut self) {
|
||||||
|
self.line_status.insert(IrqLineStatus::IRQ_NOPROBE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn clear_noprobe(&mut self) {
|
||||||
|
self.line_status.remove(IrqLineStatus::IRQ_NOPROBE);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_nothread(&mut self) {
|
||||||
|
self.line_status.insert(IrqLineStatus::IRQ_NOTHREAD);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_nothread(&mut self) {
|
||||||
|
self.line_status.remove(IrqLineStatus::IRQ_NOTHREAD);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn nested_thread(&self) -> bool {
|
pub fn nested_thread(&self) -> bool {
|
||||||
self.line_status.contains(IrqLineStatus::IRQ_NESTED_THREAD)
|
self.line_status.contains(IrqLineStatus::IRQ_NESTED_THREAD)
|
||||||
}
|
}
|
||||||
@ -404,6 +466,14 @@ impl InnerIrqDesc {
|
|||||||
self.actions.push(action);
|
self.actions.push(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clear_actions(&mut self) {
|
||||||
|
self.actions.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_action(&mut self, action: &Arc<IrqAction>) {
|
||||||
|
self.actions.retain(|a| !Arc::ptr_eq(a, action));
|
||||||
|
}
|
||||||
|
|
||||||
pub fn internal_state(&self) -> &IrqDescState {
|
pub fn internal_state(&self) -> &IrqDescState {
|
||||||
&self.desc_internal_state
|
&self.desc_internal_state
|
||||||
}
|
}
|
||||||
@ -445,6 +515,22 @@ impl InnerIrqDesc {
|
|||||||
pub fn set_level(&mut self) {
|
pub fn set_level(&mut self) {
|
||||||
self.line_status.insert(IrqLineStatus::IRQ_LEVEL);
|
self.line_status.insert(IrqLineStatus::IRQ_LEVEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn percpu_enabled(&self) -> &Option<CpuMask> {
|
||||||
|
&self.percpu_enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn percpu_enabled_mut(&mut self) -> &mut Option<CpuMask> {
|
||||||
|
&mut self.percpu_enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn percpu_affinity(&self) -> &Option<CpuMask> {
|
||||||
|
&self.percpu_affinity
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn percpu_affinity_mut(&mut self) -> &mut Option<CpuMask> {
|
||||||
|
&mut self.percpu_affinity
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KObject for IrqDesc {
|
impl KObject for IrqDesc {
|
||||||
@ -548,6 +634,7 @@ impl IrqAction {
|
|||||||
let action: IrqAction = IrqAction {
|
let action: IrqAction = IrqAction {
|
||||||
inner: SpinLock::new(InnerIrqAction {
|
inner: SpinLock::new(InnerIrqAction {
|
||||||
dev_id: None,
|
dev_id: None,
|
||||||
|
per_cpu_dev_id: None,
|
||||||
handler,
|
handler,
|
||||||
thread_fn,
|
thread_fn,
|
||||||
thread: None,
|
thread: None,
|
||||||
@ -577,6 +664,8 @@ impl IrqAction {
|
|||||||
pub struct InnerIrqAction {
|
pub struct InnerIrqAction {
|
||||||
/// cookie to identify the device
|
/// cookie to identify the device
|
||||||
dev_id: Option<Arc<DeviceId>>,
|
dev_id: Option<Arc<DeviceId>>,
|
||||||
|
/// cookie to identify the device (per cpu)
|
||||||
|
per_cpu_dev_id: Option<PerCpuVar<Arc<DeviceId>>>,
|
||||||
/// 中断处理程序
|
/// 中断处理程序
|
||||||
handler: Option<&'static dyn IrqHandler>,
|
handler: Option<&'static dyn IrqHandler>,
|
||||||
/// interrupt handler function for threaded interrupts
|
/// interrupt handler function for threaded interrupts
|
||||||
@ -603,6 +692,15 @@ impl InnerIrqAction {
|
|||||||
&mut self.dev_id
|
&mut self.dev_id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn per_cpu_dev_id(&self) -> Option<&Arc<DeviceId>> {
|
||||||
|
self.per_cpu_dev_id.as_ref().map(|v| v.get())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn per_cpu_dev_id_mut(&mut self) -> Option<&mut Arc<DeviceId>> {
|
||||||
|
self.per_cpu_dev_id.as_mut().map(|v| v.get_mut())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn handler(&self) -> Option<&'static dyn IrqHandler> {
|
pub fn handler(&self) -> Option<&'static dyn IrqHandler> {
|
||||||
self.handler
|
self.handler
|
||||||
}
|
}
|
||||||
@ -798,6 +896,42 @@ impl IrqDescManager {
|
|||||||
self.irq_descs.get(&irq).map(|desc| desc.clone())
|
self.irq_descs.get(&irq).map(|desc| desc.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 查找中断描述符并锁定总线(没有对irqdesc进行加锁)
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn lookup_and_lock_bus(
|
||||||
|
&self,
|
||||||
|
irq: IrqNumber,
|
||||||
|
check_global: bool,
|
||||||
|
check_percpu: bool,
|
||||||
|
) -> Option<Arc<IrqDesc>> {
|
||||||
|
self.do_lookup_and_lock(irq, true, check_global, check_percpu)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_lookup_and_lock(
|
||||||
|
&self,
|
||||||
|
irq: IrqNumber,
|
||||||
|
lock_bus: bool,
|
||||||
|
check_global: bool,
|
||||||
|
check_percpu: bool,
|
||||||
|
) -> Option<Arc<IrqDesc>> {
|
||||||
|
let desc = self.lookup(irq)?;
|
||||||
|
if check_global || check_percpu {
|
||||||
|
if check_percpu && !desc.inner().line_status().is_per_cpu_devid() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if check_global && desc.inner().line_status().is_per_cpu_devid() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if lock_bus {
|
||||||
|
desc.chip_bus_lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Some(desc);
|
||||||
|
}
|
||||||
|
|
||||||
fn insert(&mut self, irq: IrqNumber, desc: Arc<IrqDesc>) {
|
fn insert(&mut self, irq: IrqNumber, desc: Arc<IrqDesc>) {
|
||||||
self.irq_descs.insert(irq, desc);
|
self.irq_descs.insert(irq, desc);
|
||||||
}
|
}
|
||||||
@ -815,4 +949,41 @@ impl IrqDescManager {
|
|||||||
pub fn iter_descs(&self) -> btree_map::Iter<'_, IrqNumber, Arc<IrqDesc>> {
|
pub fn iter_descs(&self) -> btree_map::Iter<'_, IrqNumber, Arc<IrqDesc>> {
|
||||||
self.irq_descs.iter()
|
self.irq_descs.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 设置指定irq的可用cpu为所有cpu
|
||||||
|
pub fn set_percpu_devid_all(&self, irq: IrqNumber) -> Result<(), SystemError> {
|
||||||
|
self.set_percpu_devid(irq, None)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 设置指定irq的可用cpu
|
||||||
|
///
|
||||||
|
/// 如果affinity为None,则表示设置为所有cpu
|
||||||
|
pub fn set_percpu_devid(
|
||||||
|
&self,
|
||||||
|
irq: IrqNumber,
|
||||||
|
affinity: Option<&CpuMask>,
|
||||||
|
) -> Result<(), SystemError> {
|
||||||
|
let desc = self.lookup(irq).ok_or(SystemError::EINVAL)?;
|
||||||
|
let mut desc_inner = desc.inner();
|
||||||
|
|
||||||
|
if desc_inner.percpu_enabled().is_some() {
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
*desc_inner.percpu_enabled_mut() = Some(CpuMask::new());
|
||||||
|
|
||||||
|
if let Some(affinity) = affinity {
|
||||||
|
desc_inner.percpu_affinity_mut().replace(affinity.clone());
|
||||||
|
} else {
|
||||||
|
desc_inner
|
||||||
|
.percpu_affinity_mut()
|
||||||
|
.replace(smp_cpu_manager().possible_cpus().clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
drop(desc_inner);
|
||||||
|
|
||||||
|
desc.set_percpu_devid_flags();
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,10 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
irqchip::{IrqChipGeneric, IrqGcFlags},
|
dummychip::no_irq_chip,
|
||||||
irqdata::IrqData,
|
irqchip::{IrqChip, IrqChipData, IrqChipGeneric, IrqGcFlags},
|
||||||
|
irqdata::{IrqData, IrqHandlerData},
|
||||||
|
irqdesc::IrqFlowHandler,
|
||||||
HardwareIrqNumber, IrqNumber,
|
HardwareIrqNumber, IrqNumber,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -49,6 +51,31 @@ impl IrqDomainManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 创建一个新的线性映射的irqdomain, 并将其添加到irqdomain管理器中
|
||||||
|
///
|
||||||
|
/// 创建的irqdomain,中断号是线性的,即从0开始,依次递增
|
||||||
|
///
|
||||||
|
/// ## 参数
|
||||||
|
///
|
||||||
|
/// - `name` - 中断域的名字
|
||||||
|
/// - `ops` - 中断域的操作
|
||||||
|
/// - `irq_size` - 中断号的数量
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn create_and_add_linear(
|
||||||
|
&self,
|
||||||
|
name: String,
|
||||||
|
ops: &'static dyn IrqDomainOps,
|
||||||
|
irq_size: u32,
|
||||||
|
) -> Option<Arc<IrqDomain>> {
|
||||||
|
self.create_and_add(
|
||||||
|
name,
|
||||||
|
ops,
|
||||||
|
IrqNumber::new(0),
|
||||||
|
HardwareIrqNumber::new(0),
|
||||||
|
irq_size,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// 创建一个新的irqdomain, 并将其添加到irqdomain管理器中
|
/// 创建一个新的irqdomain, 并将其添加到irqdomain管理器中
|
||||||
///
|
///
|
||||||
/// ## 参数
|
/// ## 参数
|
||||||
@ -272,6 +299,97 @@ impl IrqDomainManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `irq_domain_set_info` - 在 @domain 中为 @virq 设置完整的数据
|
||||||
|
///
|
||||||
|
/// ## 参数
|
||||||
|
///
|
||||||
|
/// - `domain`: 要匹配的中断域
|
||||||
|
/// - `virq`: IRQ号
|
||||||
|
/// - `hwirq`: 硬件中断号
|
||||||
|
/// - `chip`: 相关的中断芯片
|
||||||
|
/// - `chip_data`: 相关的中断芯片数据
|
||||||
|
/// - `handler`: 中断流处理器
|
||||||
|
/// - `handler_data`: 中断流处理程序数据
|
||||||
|
/// - `handler_name`: 中断处理程序名称
|
||||||
|
pub fn domain_set_info(
|
||||||
|
&self,
|
||||||
|
domain: &Arc<IrqDomain>,
|
||||||
|
virq: IrqNumber,
|
||||||
|
hwirq: HardwareIrqNumber,
|
||||||
|
chip: Arc<dyn IrqChip>,
|
||||||
|
chip_data: Option<Arc<dyn IrqChipData>>,
|
||||||
|
flow_handler: &'static dyn IrqFlowHandler,
|
||||||
|
handler_data: Option<Arc<dyn IrqHandlerData>>,
|
||||||
|
handler_name: Option<String>,
|
||||||
|
) {
|
||||||
|
let r = self.domain_set_hwirq_and_chip(domain, virq, hwirq, Some(chip), chip_data);
|
||||||
|
if r.is_err() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
irq_manager().__irq_set_handler(virq, flow_handler, false, handler_name);
|
||||||
|
irq_manager().irq_set_handler_data(virq, handler_data).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `domain_set_hwirq_and_chip` - 在 @domain 中为 @virq 设置 hwirq 和 irqchip
|
||||||
|
///
|
||||||
|
/// ## 参数
|
||||||
|
///
|
||||||
|
/// - `domain`: 要匹配的中断域
|
||||||
|
/// - `virq`: IRQ号
|
||||||
|
/// - `hwirq`: hwirq号
|
||||||
|
/// - `chip`: 相关的中断芯片
|
||||||
|
/// - `chip_data`: 相关的芯片数据
|
||||||
|
pub fn domain_set_hwirq_and_chip(
|
||||||
|
&self,
|
||||||
|
domain: &Arc<IrqDomain>,
|
||||||
|
virq: IrqNumber,
|
||||||
|
hwirq: HardwareIrqNumber,
|
||||||
|
chip: Option<Arc<dyn IrqChip>>,
|
||||||
|
chip_data: Option<Arc<dyn IrqChipData>>,
|
||||||
|
) -> Result<(), SystemError> {
|
||||||
|
let irq_data: Arc<IrqData> = self
|
||||||
|
.domain_get_irq_data(domain, virq)
|
||||||
|
.ok_or(SystemError::ENOENT)?;
|
||||||
|
let mut inner = irq_data.inner();
|
||||||
|
let mut chip_info = irq_data.chip_info_write_irqsave();
|
||||||
|
|
||||||
|
inner.set_hwirq(hwirq);
|
||||||
|
if let Some(chip) = chip {
|
||||||
|
chip_info.set_chip(Some(chip));
|
||||||
|
} else {
|
||||||
|
chip_info.set_chip(Some(no_irq_chip()));
|
||||||
|
};
|
||||||
|
|
||||||
|
chip_info.set_chip_data(chip_data);
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `irq_domain_get_irq_data` - 获取与 @virq 和 @domain 关联的 irq_data
|
||||||
|
///
|
||||||
|
/// ## 参数
|
||||||
|
///
|
||||||
|
/// - `domain`: 要匹配的域
|
||||||
|
/// - `virq`: 要获取 irq_data 的IRQ号
|
||||||
|
pub fn domain_get_irq_data(
|
||||||
|
&self,
|
||||||
|
domain: &Arc<IrqDomain>,
|
||||||
|
virq: IrqNumber,
|
||||||
|
) -> Option<Arc<IrqData>> {
|
||||||
|
let desc = irq_desc_manager().lookup(virq)?;
|
||||||
|
let mut irq_data = Some(desc.irq_data());
|
||||||
|
|
||||||
|
while irq_data.is_some() {
|
||||||
|
let dt = irq_data.unwrap();
|
||||||
|
if dt.domain().is_some() && Arc::ptr_eq(dt.domain().as_ref().unwrap(), domain) {
|
||||||
|
return Some(dt);
|
||||||
|
}
|
||||||
|
irq_data = dt.parent_data().map(|x| x.upgrade()).flatten();
|
||||||
|
}
|
||||||
|
|
||||||
|
return None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct InnerIrqDomainManager {
|
struct InnerIrqDomainManager {
|
||||||
@ -299,6 +417,8 @@ pub struct IrqDomain {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct InnerIrqDomain {
|
struct InnerIrqDomain {
|
||||||
|
/// this field not touched by the core code
|
||||||
|
host_data: Option<Arc<dyn IrqChipData>>,
|
||||||
/// host per irq_domain flags
|
/// host per irq_domain flags
|
||||||
flags: IrqDomainFlags,
|
flags: IrqDomainFlags,
|
||||||
/// The number of mapped interrupts
|
/// The number of mapped interrupts
|
||||||
@ -335,6 +455,7 @@ impl IrqDomain {
|
|||||||
allocated_name: SpinLock::new(allocated_name),
|
allocated_name: SpinLock::new(allocated_name),
|
||||||
ops,
|
ops,
|
||||||
inner: SpinLock::new(InnerIrqDomain {
|
inner: SpinLock::new(InnerIrqDomain {
|
||||||
|
host_data: None,
|
||||||
flags,
|
flags,
|
||||||
mapcount: 0,
|
mapcount: 0,
|
||||||
bus_token,
|
bus_token,
|
||||||
@ -380,6 +501,14 @@ impl IrqDomain {
|
|||||||
pub fn map_count(&self) -> u32 {
|
pub fn map_count(&self) -> u32 {
|
||||||
self.revmap.read().map.len() as u32
|
self.revmap.read().map.len() as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn host_data(&self) -> Option<Arc<dyn IrqChipData>> {
|
||||||
|
self.inner.lock_irqsave().host_data.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_host_data(&self, host_data: Option<Arc<dyn IrqChipData>>) {
|
||||||
|
self.inner.lock_irqsave().host_data = host_data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#190
|
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#190
|
||||||
@ -458,10 +587,12 @@ pub trait IrqDomainOps: Debug + Send + Sync {
|
|||||||
/// 匹配一个中断控制器设备节点到一个主机。
|
/// 匹配一个中断控制器设备节点到一个主机。
|
||||||
fn match_node(
|
fn match_node(
|
||||||
&self,
|
&self,
|
||||||
irq_domain: &Arc<IrqDomain>,
|
_irq_domain: &Arc<IrqDomain>,
|
||||||
device_node: &Arc<DeviceNode>,
|
_device_node: &Arc<DeviceNode>,
|
||||||
bus_token: IrqDomainBusToken,
|
_bus_token: IrqDomainBusToken,
|
||||||
) -> bool;
|
) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
/// 创建或更新一个虚拟中断号与一个硬件中断号之间的映射。
|
/// 创建或更新一个虚拟中断号与一个硬件中断号之间的映射。
|
||||||
/// 对于给定的映射,这只会被调用一次。
|
/// 对于给定的映射,这只会被调用一次。
|
||||||
|
@ -451,7 +451,7 @@ impl IrqManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 激活中断。这种激活必须独立于IRQ_NOAUTOEN进行*desc_inner_guard.internal_state_mut() |= IrqDescState::IRQS_NOREQUEST;uest.
|
// 激活中断。这种激活必须独立于IRQ_NOAUTOEN进行*desc_inner_guard.internal_state_mut() |= IrqDescState::IRQS_NOREQUEST;uest.
|
||||||
if let Err(e) = self.irq_activate(desc.clone(), &mut desc_inner_guard) {
|
if let Err(e) = self.irq_activate(&desc, &mut desc_inner_guard) {
|
||||||
return Err(err_out_unlock(
|
return Err(err_out_unlock(
|
||||||
e,
|
e,
|
||||||
desc_inner_guard,
|
desc_inner_guard,
|
||||||
@ -499,7 +499,7 @@ impl IrqManager {
|
|||||||
{
|
{
|
||||||
// 如果没有设置IRQF_NOAUTOEN,则自动使能中断
|
// 如果没有设置IRQF_NOAUTOEN,则自动使能中断
|
||||||
self.irq_startup(
|
self.irq_startup(
|
||||||
desc.clone(),
|
&desc,
|
||||||
&mut desc_inner_guard,
|
&mut desc_inner_guard,
|
||||||
Self::IRQ_RESEND,
|
Self::IRQ_RESEND,
|
||||||
Self::IRQ_START_COND,
|
Self::IRQ_START_COND,
|
||||||
@ -598,9 +598,19 @@ impl IrqManager {
|
|||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn irq_activate_and_startup(
|
||||||
|
&self,
|
||||||
|
desc: &Arc<IrqDesc>,
|
||||||
|
desc_inner_guard: &mut SpinLockGuard<'_, InnerIrqDesc>,
|
||||||
|
resend: bool,
|
||||||
|
) -> Result<(), SystemError> {
|
||||||
|
self.irq_activate(desc, desc_inner_guard)?;
|
||||||
|
self.irq_startup(desc, desc_inner_guard, resend, Self::IRQ_START_FORCE)
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn irq_activate(
|
pub(super) fn irq_activate(
|
||||||
&self,
|
&self,
|
||||||
_desc: Arc<IrqDesc>,
|
_desc: &Arc<IrqDesc>,
|
||||||
desc_inner_guard: &mut SpinLockGuard<'_, InnerIrqDesc>,
|
desc_inner_guard: &mut SpinLockGuard<'_, InnerIrqDesc>,
|
||||||
) -> Result<(), SystemError> {
|
) -> Result<(), SystemError> {
|
||||||
let irq_data = desc_inner_guard.irq_data();
|
let irq_data = desc_inner_guard.irq_data();
|
||||||
@ -615,7 +625,7 @@ impl IrqManager {
|
|||||||
/// 设置CPU亲和性并开启中断
|
/// 设置CPU亲和性并开启中断
|
||||||
pub(super) fn irq_startup(
|
pub(super) fn irq_startup(
|
||||||
&self,
|
&self,
|
||||||
desc: Arc<IrqDesc>,
|
desc: &Arc<IrqDesc>,
|
||||||
desc_inner_guard: &mut SpinLockGuard<'_, InnerIrqDesc>,
|
desc_inner_guard: &mut SpinLockGuard<'_, InnerIrqDesc>,
|
||||||
resend: bool,
|
resend: bool,
|
||||||
force: bool,
|
force: bool,
|
||||||
@ -636,7 +646,7 @@ impl IrqManager {
|
|||||||
.flags()
|
.flags()
|
||||||
.contains(IrqChipFlags::IRQCHIP_AFFINITY_PRE_STARTUP)
|
.contains(IrqChipFlags::IRQCHIP_AFFINITY_PRE_STARTUP)
|
||||||
{
|
{
|
||||||
self.irq_setup_affinity(&desc, desc_inner_guard).ok();
|
self.irq_setup_affinity(desc, desc_inner_guard).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = self.__irq_startup(desc_inner_guard);
|
ret = self.__irq_startup(desc_inner_guard);
|
||||||
@ -647,7 +657,7 @@ impl IrqManager {
|
|||||||
.flags()
|
.flags()
|
||||||
.contains(IrqChipFlags::IRQCHIP_AFFINITY_PRE_STARTUP)
|
.contains(IrqChipFlags::IRQCHIP_AFFINITY_PRE_STARTUP)
|
||||||
{
|
{
|
||||||
self.irq_setup_affinity(&desc, desc_inner_guard).ok();
|
self.irq_setup_affinity(desc, desc_inner_guard).ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IrqStartupResult::Managed => {
|
IrqStartupResult::Managed => {
|
||||||
|
@ -18,7 +18,7 @@ use crate::{
|
|||||||
mm::init::mm_init,
|
mm::init::mm_init,
|
||||||
process::{kthread::kthread_init, process_init, ProcessManager},
|
process::{kthread::kthread_init, process_init, ProcessManager},
|
||||||
sched::{core::sched_init, SchedArch},
|
sched::{core::sched_init, SchedArch},
|
||||||
smp::SMPArch,
|
smp::{early_smp_init, SMPArch},
|
||||||
syscall::Syscall,
|
syscall::Syscall,
|
||||||
time::{
|
time::{
|
||||||
clocksource::clocksource_boot_finish, timekeeping::timekeeping_init, timer::timer_init,
|
clocksource::clocksource_boot_finish, timekeeping::timekeeping_init, timer::timer_init,
|
||||||
@ -47,12 +47,20 @@ fn do_start_kernel() {
|
|||||||
|
|
||||||
early_setup_arch().expect("setup_arch failed");
|
early_setup_arch().expect("setup_arch failed");
|
||||||
unsafe { mm_init() };
|
unsafe { mm_init() };
|
||||||
|
|
||||||
scm_reinit().unwrap();
|
scm_reinit().unwrap();
|
||||||
textui_init().unwrap();
|
textui_init().unwrap();
|
||||||
init_intertrait();
|
init_intertrait();
|
||||||
|
|
||||||
vfs_init().expect("vfs init failed");
|
vfs_init().expect("vfs init failed");
|
||||||
driver_init().expect("driver init failed");
|
driver_init().expect("driver init failed");
|
||||||
unsafe { acpi_init() };
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
unsafe {
|
||||||
|
acpi_init()
|
||||||
|
};
|
||||||
|
|
||||||
|
early_smp_init().expect("early smp init failed");
|
||||||
irq_init().expect("irq init failed");
|
irq_init().expect("irq init failed");
|
||||||
CurrentSMPArch::prepare_cpus().expect("prepare_cpus failed");
|
CurrentSMPArch::prepare_cpus().expect("prepare_cpus failed");
|
||||||
|
|
||||||
|
@ -409,12 +409,22 @@ pub fn scm_disable_put_to_window() {
|
|||||||
/// 当内存管理单元被初始化之后,重新处理帧缓冲区问题
|
/// 当内存管理单元被初始化之后,重新处理帧缓冲区问题
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
pub fn scm_reinit() -> Result<(), SystemError> {
|
pub fn scm_reinit() -> Result<(), SystemError> {
|
||||||
let r = true_scm_reinit();
|
#[cfg(target_arch = "x86_64")]
|
||||||
if r.is_err() {
|
{
|
||||||
send_to_default_serial8250_port("scm reinit failed.\n\0".as_bytes());
|
let r = true_scm_reinit();
|
||||||
|
if r.is_err() {
|
||||||
|
send_to_default_serial8250_port("scm reinit failed.\n\0".as_bytes());
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "x86_64"))]
|
||||||
|
{
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
fn true_scm_reinit() -> Result<(), SystemError> {
|
fn true_scm_reinit() -> Result<(), SystemError> {
|
||||||
video_refresh_manager()
|
video_refresh_manager()
|
||||||
.video_reinitialize(false)
|
.video_reinitialize(false)
|
||||||
|
@ -1085,6 +1085,7 @@ pub fn textui_putstr(
|
|||||||
/// 初始化text ui框架
|
/// 初始化text ui框架
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
pub fn textui_init() -> Result<i32, SystemError> {
|
pub fn textui_init() -> Result<i32, SystemError> {
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
textui_framwork_init();
|
textui_framwork_init();
|
||||||
|
|
||||||
return Ok(0);
|
return Ok(0);
|
||||||
|
@ -3,8 +3,9 @@ use core::sync::atomic::AtomicU32;
|
|||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
include::bindings::bindings::smp_get_total_cpu, libs::lazy_init::Lazy,
|
include::bindings::bindings::smp_get_total_cpu,
|
||||||
smp::core::smp_get_processor_id,
|
libs::lazy_init::Lazy,
|
||||||
|
smp::{core::smp_get_processor_id, cpu::ProcessorId},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// 系统中的CPU数量
|
/// 系统中的CPU数量
|
||||||
@ -83,6 +84,14 @@ impl<T> PerCpuVar<T> {
|
|||||||
let cpu_id = smp_get_processor_id();
|
let cpu_id = smp_get_processor_id();
|
||||||
&mut self.inner[cpu_id.data() as usize]
|
&mut self.inner[cpu_id.data() as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub unsafe fn force_get(&self, cpu_id: ProcessorId) -> &T {
|
||||||
|
&self.inner[cpu_id.data() as usize]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn force_get_mut(&mut self, cpu_id: ProcessorId) -> &mut T {
|
||||||
|
&mut self.inner[cpu_id.data() as usize]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// PerCpu变量是线程安全的,因为每个CPU都有自己的变量。
|
/// PerCpu变量是线程安全的,因为每个CPU都有自己的变量。
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
use core::sync::atomic::AtomicU32;
|
use core::sync::atomic::AtomicU32;
|
||||||
|
|
||||||
|
use crate::libs::cpumask::CpuMask;
|
||||||
|
|
||||||
mod c_adapter;
|
mod c_adapter;
|
||||||
|
|
||||||
int_like!(ProcessorId, AtomicProcessorId, u32, AtomicU32);
|
int_like!(ProcessorId, AtomicProcessorId, u32, AtomicU32);
|
||||||
@ -7,3 +9,51 @@ int_like!(ProcessorId, AtomicProcessorId, u32, AtomicU32);
|
|||||||
impl ProcessorId {
|
impl ProcessorId {
|
||||||
pub const INVALID: ProcessorId = ProcessorId::new(u32::MAX);
|
pub const INVALID: ProcessorId = ProcessorId::new(u32::MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static mut SMP_CPU_MANAGER: Option<SmpCpuManager> = None;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn smp_cpu_manager() -> &'static SmpCpuManager {
|
||||||
|
unsafe { SMP_CPU_MANAGER.as_ref().unwrap() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SmpCpuManager {
|
||||||
|
possible_cpus: CpuMask,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SmpCpuManager {
|
||||||
|
fn new() -> Self {
|
||||||
|
let possible_cpus = CpuMask::new();
|
||||||
|
Self { possible_cpus }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 设置可用的CPU
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// - 该函数不会检查CPU的有效性,调用者需要保证CPU的有效性。
|
||||||
|
/// - 由于possible_cpus是一个全局变量,且为了性能考虑,并不会加锁
|
||||||
|
/// 访问,因此该函数只能在初始化阶段调用。
|
||||||
|
pub unsafe fn set_possible_cpu(&self, cpu: ProcessorId, value: bool) {
|
||||||
|
// 强制获取mut引用,因为该函数只能在初始化阶段调用
|
||||||
|
let p = (self as *const Self as *mut Self).as_mut().unwrap();
|
||||||
|
|
||||||
|
p.possible_cpus.set(cpu, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 获取可用的CPU
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn possible_cpus(&self) -> &CpuMask {
|
||||||
|
&self.possible_cpus
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn smp_cpu_manager_init(boot_cpu: ProcessorId) {
|
||||||
|
unsafe {
|
||||||
|
SMP_CPU_MANAGER = Some(SmpCpuManager::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe { smp_cpu_manager().set_possible_cpu(boot_cpu, true) };
|
||||||
|
|
||||||
|
SmpCpuManager::arch_init(boot_cpu);
|
||||||
|
}
|
||||||
|
@ -5,7 +5,10 @@ use crate::{
|
|||||||
exception::ipi::{IpiKind, IpiTarget},
|
exception::ipi::{IpiKind, IpiTarget},
|
||||||
};
|
};
|
||||||
|
|
||||||
use self::cpu::ProcessorId;
|
use self::{
|
||||||
|
core::smp_get_processor_id,
|
||||||
|
cpu::{smp_cpu_manager_init, ProcessorId},
|
||||||
|
};
|
||||||
|
|
||||||
pub mod c_adapter;
|
pub mod c_adapter;
|
||||||
pub mod core;
|
pub mod core;
|
||||||
@ -29,3 +32,11 @@ pub trait SMPArch {
|
|||||||
/// 该函数需要标记为 `#[inline(never)]`
|
/// 该函数需要标记为 `#[inline(never)]`
|
||||||
fn init() -> Result<(), SystemError>;
|
fn init() -> Result<(), SystemError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 早期SMP初始化
|
||||||
|
#[inline(never)]
|
||||||
|
pub fn early_smp_init() -> Result<(), SystemError> {
|
||||||
|
smp_cpu_manager_init(smp_get_processor_id());
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user