mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-09 02:46:47 +00:00
parent
ce5850adbf
commit
3bc96fa4a9
@ -1,6 +1,6 @@
|
|||||||
use system_error::SystemError;
|
use system_error::SystemError;
|
||||||
|
|
||||||
use crate::exception::{InterruptArch, IrqFlags, IrqFlagsGuard};
|
use crate::exception::{InterruptArch, IrqFlags, IrqFlagsGuard, IrqNumber};
|
||||||
|
|
||||||
pub mod ipi;
|
pub mod ipi;
|
||||||
|
|
||||||
@ -35,6 +35,15 @@ impl InterruptArch for RiscV64InterruptArch {
|
|||||||
riscv::register::sstatus::clear_sie();
|
riscv::register::sstatus::clear_sie();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn probe_total_irq_num() -> u32 {
|
||||||
|
// todo: 获取中断总数
|
||||||
|
256
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ack_bad_irq(irq: IrqNumber) {
|
||||||
|
todo!("ack_bad_irq: {}", irq.data());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 中断栈帧结构体
|
/// 中断栈帧结构体
|
||||||
|
@ -12,7 +12,8 @@ use system_error::SystemError;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::CurrentIrqArch,
|
arch::CurrentIrqArch,
|
||||||
exception::{InterruptArch, IrqFlags, IrqFlagsGuard},
|
exception::{InterruptArch, IrqFlags, IrqFlagsGuard, IrqNumber},
|
||||||
|
kerror,
|
||||||
};
|
};
|
||||||
|
|
||||||
use self::entry::setup_interrupt_gate;
|
use self::entry::setup_interrupt_gate;
|
||||||
@ -78,6 +79,17 @@ impl InterruptArch for X86_64InterruptArch {
|
|||||||
local_irq_restore(flags.flags());
|
local_irq_restore(flags.flags());
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn probe_total_irq_num() -> u32 {
|
||||||
|
// todo: 从APIC获取
|
||||||
|
// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/arch/x86/kernel/apic/vector.c?r=&mo=19514&fi=704#704
|
||||||
|
256
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ack_bad_irq(irq: IrqNumber) {
|
||||||
|
kerror!("Unexpected IRQ trap at vector {}", irq.data());
|
||||||
|
CurrentApic.send_eoi();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 中断栈帧结构体
|
/// 中断栈帧结构体
|
||||||
|
@ -873,3 +873,45 @@ impl DeviceMatcher<&str> for DeviceMatchName {
|
|||||||
return device.name() == data;
|
return device.name() == data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Cookie to identify the device
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct DeviceId {
|
||||||
|
data: Option<&'static str>,
|
||||||
|
allocated: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeviceId {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn new(data: Option<&'static str>, allocated: Option<String>) -> Option<Self> {
|
||||||
|
if data.is_none() && allocated.is_none() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果data和allocated都有值,那么返回None
|
||||||
|
if data.is_some() && allocated.is_some() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Some(Self { data, allocated });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn id(&self) -> Option<&str> {
|
||||||
|
if self.data.is_some() {
|
||||||
|
return Some(self.data.unwrap());
|
||||||
|
} else {
|
||||||
|
return self.allocated.as_deref();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_allocated(&mut self, allocated: String) {
|
||||||
|
self.allocated = Some(allocated);
|
||||||
|
self.data = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for DeviceId {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
return self.id() == other.id();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
111
kernel/src/exception/dummychip.rs
Normal file
111
kernel/src/exception/dummychip.rs
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
use alloc::sync::Arc;
|
||||||
|
use system_error::SystemError;
|
||||||
|
|
||||||
|
use crate::arch::CurrentIrqArch;
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
irqchip::{IrqChip, IrqChipFlags},
|
||||||
|
irqdata::IrqData,
|
||||||
|
InterruptArch,
|
||||||
|
};
|
||||||
|
|
||||||
|
static mut NO_IRQ_CHIP: Option<Arc<NoIrqChip>> = None;
|
||||||
|
static mut DUMMY_IRQ_CHIP: Option<Arc<DummyIrqChip>> = None;
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
pub fn no_irq_chip() -> Arc<dyn IrqChip> {
|
||||||
|
unsafe { NO_IRQ_CHIP.as_ref().unwrap().clone() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[inline(never)]
|
||||||
|
pub fn dummy_irq_chip() -> Arc<dyn IrqChip> {
|
||||||
|
unsafe { DUMMY_IRQ_CHIP.as_ref().unwrap().clone() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ack_bad(irq_data: &Arc<IrqData>) {
|
||||||
|
// todo: print_irq_desc
|
||||||
|
CurrentIrqArch::ack_bad_irq(irq_data.irq());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct NoIrqChip;
|
||||||
|
|
||||||
|
impl NoIrqChip {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
NoIrqChip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IrqChip for NoIrqChip {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"none"
|
||||||
|
}
|
||||||
|
fn irq_enable(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn irq_disable(&self, _irq: &Arc<IrqData>) {}
|
||||||
|
|
||||||
|
fn irq_ack(&self, irq: &Arc<IrqData>) {
|
||||||
|
ack_bad(irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn irq_startup(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn irq_shutdown(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flags(&self) -> IrqChipFlags {
|
||||||
|
IrqChipFlags::IRQCHIP_SKIP_SET_WAKE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct DummyIrqChip;
|
||||||
|
|
||||||
|
impl DummyIrqChip {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
DummyIrqChip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IrqChip for DummyIrqChip {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"dummy"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn irq_enable(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn irq_disable(&self, _irq: &Arc<IrqData>) {}
|
||||||
|
|
||||||
|
fn irq_ack(&self, _irq: &Arc<IrqData>) {}
|
||||||
|
|
||||||
|
fn irq_mask(&self, _irq: &Arc<IrqData>) {}
|
||||||
|
fn irq_unmask(&self, _irq: &Arc<IrqData>) {}
|
||||||
|
|
||||||
|
fn irq_startup(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn irq_shutdown(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flags(&self) -> IrqChipFlags {
|
||||||
|
IrqChipFlags::IRQCHIP_SKIP_SET_WAKE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
pub fn dummy_chip_init() {
|
||||||
|
unsafe {
|
||||||
|
NO_IRQ_CHIP = Some(Arc::new(NoIrqChip::new()));
|
||||||
|
DUMMY_IRQ_CHIP = Some(Arc::new(DummyIrqChip::new()));
|
||||||
|
}
|
||||||
|
}
|
27
kernel/src/exception/handle.rs
Normal file
27
kernel/src/exception/handle.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
use alloc::sync::Arc;
|
||||||
|
|
||||||
|
use crate::arch::CurrentIrqArch;
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
irqdesc::{IrqDesc, IrqFlowHandler},
|
||||||
|
InterruptArch,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// 获取用于处理错误的中断的处理程序
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn bad_irq_handler() -> &'static dyn IrqFlowHandler {
|
||||||
|
&HandleBadIrq
|
||||||
|
}
|
||||||
|
|
||||||
|
/// handle spurious and unhandled irqs
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct HandleBadIrq;
|
||||||
|
|
||||||
|
impl IrqFlowHandler for HandleBadIrq {
|
||||||
|
/// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/handle.c?fi=handle_bad_irq#33
|
||||||
|
fn handle(&self, irq_desc: &Arc<IrqDesc>) {
|
||||||
|
// todo: print_irq_desc
|
||||||
|
// todo: 增加kstat计数
|
||||||
|
CurrentIrqArch::ack_bad_irq(irq_desc.irq());
|
||||||
|
}
|
||||||
|
}
|
@ -2,13 +2,16 @@ use system_error::SystemError;
|
|||||||
|
|
||||||
use crate::arch::CurrentIrqArch;
|
use crate::arch::CurrentIrqArch;
|
||||||
|
|
||||||
use super::InterruptArch;
|
use super::{dummychip::dummy_chip_init, irqdesc::early_irq_init, InterruptArch};
|
||||||
|
|
||||||
/// 初始化中断
|
/// 初始化中断
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
pub fn irq_init() -> Result<(), SystemError> {
|
pub fn irq_init() -> Result<(), SystemError> {
|
||||||
// todo: 通用初始化
|
// todo: 通用初始化
|
||||||
|
|
||||||
|
dummy_chip_init();
|
||||||
|
early_irq_init().expect("early_irq_init failed");
|
||||||
|
|
||||||
// 初始化架构相关的中断
|
// 初始化架构相关的中断
|
||||||
unsafe { CurrentIrqArch::arch_irq_init() }?;
|
unsafe { CurrentIrqArch::arch_irq_init() }?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -41,18 +41,18 @@ pub trait IrqChip: Sync + Send + Any + Debug {
|
|||||||
fn irq_ack(&self, irq: &Arc<IrqData>);
|
fn irq_ack(&self, irq: &Arc<IrqData>);
|
||||||
|
|
||||||
/// mask an interrupt source
|
/// mask an interrupt source
|
||||||
fn irq_mask(&self, irq: &Arc<IrqData>);
|
fn irq_mask(&self, _irq: &Arc<IrqData>) {}
|
||||||
/// ack and mask an interrupt source
|
/// ack and mask an interrupt source
|
||||||
fn irq_mask_ack(&self, irq: &Arc<IrqData>);
|
fn irq_mask_ack(&self, _irq: &Arc<IrqData>) {}
|
||||||
/// unmask an interrupt source
|
/// unmask an interrupt source
|
||||||
fn irq_unmask(&self, irq: &Arc<IrqData>);
|
fn irq_unmask(&self, _irq: &Arc<IrqData>) {}
|
||||||
/// end of interrupt
|
/// end of interrupt
|
||||||
fn irq_eoi(&self, irq: &Arc<IrqData>);
|
fn irq_eoi(&self, _irq: &Arc<IrqData>) {}
|
||||||
|
|
||||||
// todo: set affinity
|
// todo: set affinity
|
||||||
|
|
||||||
/// retrigger an IRQ to the CPU
|
/// retrigger an IRQ to the CPU
|
||||||
fn retrigger(&self, irq: &Arc<IrqData>);
|
fn retrigger(&self, _irq: &Arc<IrqData>) {}
|
||||||
|
|
||||||
/// set the flow type of an interrupt
|
/// set the flow type of an interrupt
|
||||||
///
|
///
|
||||||
@ -83,14 +83,14 @@ pub trait IrqChip: Sync + Send + Any + Debug {
|
|||||||
|
|
||||||
/// function called from core code on suspend once per
|
/// function called from core code on suspend once per
|
||||||
/// chip, when one or more interrupts are installed
|
/// chip, when one or more interrupts are installed
|
||||||
fn irq_suspend(&self, irq: &Arc<IrqData>);
|
fn irq_suspend(&self, _irq: &Arc<IrqData>) {}
|
||||||
|
|
||||||
/// function called from core code on resume once per chip,
|
/// function called from core code on resume once per chip,
|
||||||
/// when one ore more interrupts are installed
|
/// when one ore more interrupts are installed
|
||||||
fn irq_resume(&self, irq: &Arc<IrqData>);
|
fn irq_resume(&self, _irq: &Arc<IrqData>) {}
|
||||||
|
|
||||||
/// function called from core code on shutdown once per chip
|
/// function called from core code on shutdown once per chip
|
||||||
fn irq_pm_shutdown(&self, irq: &Arc<IrqData>);
|
fn irq_pm_shutdown(&self, _irq: &Arc<IrqData>) {}
|
||||||
|
|
||||||
/// Optional function to set irq_data.mask for special cases
|
/// Optional function to set irq_data.mask for special cases
|
||||||
fn irq_calc_mask(&self, _irq: &Arc<IrqData>) {}
|
fn irq_calc_mask(&self, _irq: &Arc<IrqData>) {}
|
||||||
@ -135,7 +135,7 @@ pub trait IrqChip: Sync + Send + Any + Debug {
|
|||||||
// todo: set vcpu affinity
|
// todo: set vcpu affinity
|
||||||
|
|
||||||
/// send a single IPI to destination cpus
|
/// send a single IPI to destination cpus
|
||||||
fn send_single_ipi(&self, irq: &Arc<IrqData>, cpu: u32);
|
fn send_single_ipi(&self, _irq: &Arc<IrqData>, _cpu: u32) {}
|
||||||
|
|
||||||
// todo: send ipi with cpu mask
|
// todo: send ipi with cpu mask
|
||||||
|
|
||||||
@ -145,7 +145,9 @@ pub trait IrqChip: Sync + Send + Any + Debug {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// function called from core code after disabling an NMI
|
/// function called from core code after disabling an NMI
|
||||||
fn irq_nmi_teardown(&self, irq: &Arc<IrqData>);
|
fn irq_nmi_teardown(&self, _irq: &Arc<IrqData>) {}
|
||||||
|
|
||||||
|
fn flags(&self) -> IrqChipFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -214,7 +216,7 @@ struct InnerIrqChipGeneric {
|
|||||||
chip_types: Vec<IrqChipType>,
|
chip_types: Vec<IrqChipType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait IrqChipGenericOps: Debug {
|
pub trait IrqChipGenericOps: Debug + Send + Sync {
|
||||||
/// Alternate I/O accessor (defaults to readl if NULL)
|
/// Alternate I/O accessor (defaults to readl if NULL)
|
||||||
unsafe fn reg_readl(&self, addr: VirtAddr) -> u32;
|
unsafe fn reg_readl(&self, addr: VirtAddr) -> u32;
|
||||||
|
|
||||||
@ -237,3 +239,33 @@ pub trait IrqChipGenericPrivateData: Sync + Send + Any + Debug {}
|
|||||||
pub struct IrqChipType {
|
pub struct IrqChipType {
|
||||||
// todo https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#1024
|
// todo https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#1024
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
/// IrqChip specific flags
|
||||||
|
pub struct IrqChipFlags: u32 {
|
||||||
|
/// 在调用chip.irq_set_type()之前屏蔽
|
||||||
|
const IRQCHIP_SET_TYPE_MASKED = 1 << 0;
|
||||||
|
/// 只有在irq被处理时才发出irq_eoi()
|
||||||
|
const IRQCHIP_EOI_IF_HANDLED = 1 << 1;
|
||||||
|
/// 在挂起路径中屏蔽非唤醒irq
|
||||||
|
const IRQCHIP_MASK_ON_SUSPEND = 1 << 2;
|
||||||
|
/// 只有在irq启用时才调用irq_on/off_line回调
|
||||||
|
const IRQCHIP_ONOFFLINE_ENABLED = 1 << 3;
|
||||||
|
/// 跳过chip.irq_set_wake(),对于这个irq芯片
|
||||||
|
const IRQCHIP_SKIP_SET_WAKE = 1 << 4;
|
||||||
|
/// 单次触发不需要屏蔽/取消屏蔽
|
||||||
|
const IRQCHIP_ONESHOT_SAFE = 1 << 5;
|
||||||
|
/// 芯片在线程模式下需要在取消屏蔽时eoi()
|
||||||
|
const IRQCHIP_EOI_THREADED = 1 << 6;
|
||||||
|
/// 芯片可以为Level MSIs提供两个门铃
|
||||||
|
const IRQCHIP_SUPPORTS_LEVEL_MSI = 1 << 7;
|
||||||
|
/// 芯片可以传递NMIs,仅适用于根irqchips
|
||||||
|
const IRQCHIP_SUPPORTS_NMI = 1 << 8;
|
||||||
|
/// 在挂起路径中,如果它们处于禁用状态,则调用__enable_irq()/__disable_irq()以唤醒irq
|
||||||
|
const IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND = 1 << 9;
|
||||||
|
/// 在启动前更新默认亲和性
|
||||||
|
const IRQCHIP_AFFINITY_PRE_STARTUP = 1 << 10;
|
||||||
|
/// 不要在这个芯片中改变任何东西
|
||||||
|
const IRQCHIP_IMMUTABLE = 1 << 11;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -21,6 +21,50 @@ use super::{
|
|||||||
pub struct IrqData {
|
pub struct IrqData {
|
||||||
/// 中断号, 用于表示软件逻辑视角的中断号,全局唯一
|
/// 中断号, 用于表示软件逻辑视角的中断号,全局唯一
|
||||||
irq: IrqNumber,
|
irq: IrqNumber,
|
||||||
|
inner: SpinLock<InnerIrqData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IrqData {
|
||||||
|
pub fn new(
|
||||||
|
irq: IrqNumber,
|
||||||
|
hwirq: HardwareIrqNumber,
|
||||||
|
common_data: Arc<IrqCommonData>,
|
||||||
|
chip: Arc<dyn IrqChip>,
|
||||||
|
) -> Self {
|
||||||
|
return IrqData {
|
||||||
|
irq,
|
||||||
|
inner: SpinLock::new(InnerIrqData {
|
||||||
|
hwirq,
|
||||||
|
common_data,
|
||||||
|
chip,
|
||||||
|
chip_data: None,
|
||||||
|
domain: None,
|
||||||
|
parent_data: None,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn irqd_set(&self, status: IrqStatus) {
|
||||||
|
// clone是为了释放inner锁
|
||||||
|
let common_data = self.inner.lock().common_data.clone();
|
||||||
|
common_data.irqd_set(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn irqd_clear(&self, status: IrqStatus) {
|
||||||
|
// clone是为了释放inner锁
|
||||||
|
let common_data = self.inner.lock().common_data.clone();
|
||||||
|
common_data.irqd_clear(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn irq(&self) -> IrqNumber {
|
||||||
|
self.irq
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct InnerIrqData {
|
||||||
/// 硬件中断号, 用于表示在某个IrqDomain中的中断号
|
/// 硬件中断号, 用于表示在某个IrqDomain中的中断号
|
||||||
hwirq: HardwareIrqNumber,
|
hwirq: HardwareIrqNumber,
|
||||||
/// 涉及的所有irqchip之间共享的数据
|
/// 涉及的所有irqchip之间共享的数据
|
||||||
@ -28,9 +72,9 @@ pub struct IrqData {
|
|||||||
/// 绑定到的中断芯片
|
/// 绑定到的中断芯片
|
||||||
chip: Arc<dyn IrqChip>,
|
chip: Arc<dyn IrqChip>,
|
||||||
/// 中断芯片的私有数据(与当前irq相关)
|
/// 中断芯片的私有数据(与当前irq相关)
|
||||||
chip_data: Arc<dyn IrqChipData>,
|
chip_data: Option<Arc<dyn IrqChipData>>,
|
||||||
/// 中断域
|
/// 中断域
|
||||||
domain: Arc<IrqDomain>,
|
domain: Option<Arc<IrqDomain>>,
|
||||||
/// 中断的父中断(如果具有中断域继承的话)
|
/// 中断的父中断(如果具有中断域继承的话)
|
||||||
parent_data: Option<Weak<IrqData>>,
|
parent_data: Option<Weak<IrqData>>,
|
||||||
}
|
}
|
||||||
@ -38,12 +82,32 @@ pub struct IrqData {
|
|||||||
/// per irq data shared by all irqchips
|
/// per irq data shared by all irqchips
|
||||||
///
|
///
|
||||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#147
|
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#147
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct IrqCommonData {
|
pub struct IrqCommonData {
|
||||||
inner: SpinLock<InnerIrqCommonData>,
|
inner: SpinLock<InnerIrqCommonData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl IrqCommonData {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let inner = InnerIrqCommonData {
|
||||||
|
state: IrqStatus::empty(),
|
||||||
|
handler_data: None,
|
||||||
|
msi_desc: None,
|
||||||
|
};
|
||||||
|
return IrqCommonData {
|
||||||
|
inner: SpinLock::new(inner),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn irqd_set(&self, status: IrqStatus) {
|
||||||
|
self.inner.lock_irqsave().irqd_set(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn irqd_clear(&self, status: IrqStatus) {
|
||||||
|
self.inner.lock_irqsave().irqd_clear(status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct InnerIrqCommonData {
|
struct InnerIrqCommonData {
|
||||||
@ -55,6 +119,16 @@ struct InnerIrqCommonData {
|
|||||||
// todo: affinity
|
// todo: affinity
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl InnerIrqCommonData {
|
||||||
|
pub fn irqd_set(&mut self, status: IrqStatus) {
|
||||||
|
self.state.insert(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn irqd_clear(&mut self, status: IrqStatus) {
|
||||||
|
self.state.remove(status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait IrqHandlerData: Send + Sync + Any + Debug {}
|
pub trait IrqHandlerData: Send + Sync + Any + Debug {}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
|
294
kernel/src/exception/irqdesc.rs
Normal file
294
kernel/src/exception/irqdesc.rs
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
use core::{any::Any, fmt::Debug};
|
||||||
|
|
||||||
|
use alloc::{
|
||||||
|
collections::BTreeMap,
|
||||||
|
string::String,
|
||||||
|
sync::{Arc, Weak},
|
||||||
|
vec::Vec,
|
||||||
|
};
|
||||||
|
use system_error::SystemError;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
arch::CurrentIrqArch,
|
||||||
|
driver::base::{
|
||||||
|
device::DeviceId,
|
||||||
|
kobject::{KObjType, KObject, KObjectState, LockedKObjectState},
|
||||||
|
kset::KSet,
|
||||||
|
},
|
||||||
|
filesystem::kernfs::KernFSInode,
|
||||||
|
libs::{
|
||||||
|
rwlock::{RwLockReadGuard, RwLockWriteGuard},
|
||||||
|
spinlock::{SpinLock, SpinLockGuard},
|
||||||
|
},
|
||||||
|
process::ProcessControlBlock,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
dummychip::no_irq_chip,
|
||||||
|
handle::bad_irq_handler,
|
||||||
|
irqdata::{IrqCommonData, IrqData, IrqStatus},
|
||||||
|
sysfs::IrqKObjType,
|
||||||
|
HardwareIrqNumber, InterruptArch, IrqNumber,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// 中断流处理程序
|
||||||
|
pub trait IrqFlowHandler: Debug + Send + Sync {
|
||||||
|
fn handle(&self, irq_desc: &Arc<IrqDesc>);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdesc.h#55
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct IrqDesc {
|
||||||
|
inner: SpinLock<InnerIrqDesc>,
|
||||||
|
|
||||||
|
handler: SpinLock<Option<&'static dyn IrqFlowHandler>>,
|
||||||
|
|
||||||
|
kobj_state: LockedKObjectState,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IrqDesc {
|
||||||
|
#[inline(never)]
|
||||||
|
pub fn new(irq: IrqNumber, name: Option<String>, irqd_flags: IrqStatus) -> Arc<Self> {
|
||||||
|
// 初始化的过程参考 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/irqdesc.c#392
|
||||||
|
let common_data = Arc::new(IrqCommonData::new());
|
||||||
|
let irq_data = Arc::new(IrqData::new(
|
||||||
|
irq,
|
||||||
|
HardwareIrqNumber::new(irq.data()),
|
||||||
|
common_data.clone(),
|
||||||
|
no_irq_chip(),
|
||||||
|
));
|
||||||
|
|
||||||
|
irq_data.irqd_set(IrqStatus::IRQD_IRQ_DISABLED);
|
||||||
|
common_data.irqd_set(IrqStatus::IRQD_IRQ_MASKED);
|
||||||
|
|
||||||
|
let irq_desc = IrqDesc {
|
||||||
|
inner: SpinLock::new(InnerIrqDesc {
|
||||||
|
common_data,
|
||||||
|
irq_data,
|
||||||
|
actions: Vec::new(),
|
||||||
|
name,
|
||||||
|
parent_irq: None,
|
||||||
|
depth: 1,
|
||||||
|
wake_depth: 0,
|
||||||
|
kern_inode: None,
|
||||||
|
kset: None,
|
||||||
|
parent_kobj: None,
|
||||||
|
}),
|
||||||
|
handler: SpinLock::new(None),
|
||||||
|
kobj_state: LockedKObjectState::new(Some(KObjectState::INITIALIZED)),
|
||||||
|
};
|
||||||
|
|
||||||
|
irq_desc.set_handler(bad_irq_handler());
|
||||||
|
irq_desc.inner().irq_data.irqd_set(irqd_flags);
|
||||||
|
|
||||||
|
return Arc::new(irq_desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_handler(&self, handler: &'static dyn IrqFlowHandler) {
|
||||||
|
let mut guard = self.handler.lock_irqsave();
|
||||||
|
*guard = Some(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inner(&self) -> SpinLockGuard<InnerIrqDesc> {
|
||||||
|
self.inner.lock_irqsave()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn irq(&self) -> IrqNumber {
|
||||||
|
self.inner().irq_data.irq()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct InnerIrqDesc {
|
||||||
|
/// per irq and chip data passed down to chip functions
|
||||||
|
common_data: Arc<IrqCommonData>,
|
||||||
|
irq_data: Arc<IrqData>,
|
||||||
|
actions: Vec<Arc<IrqAction>>,
|
||||||
|
name: Option<String>,
|
||||||
|
parent_irq: Option<IrqNumber>,
|
||||||
|
/// nested irq disables
|
||||||
|
depth: u32,
|
||||||
|
/// nested wake enables
|
||||||
|
wake_depth: u32,
|
||||||
|
|
||||||
|
kern_inode: Option<Arc<KernFSInode>>,
|
||||||
|
kset: Option<Arc<KSet>>,
|
||||||
|
parent_kobj: Option<Weak<dyn KObject>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KObject for IrqDesc {
|
||||||
|
fn as_any_ref(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_inode(&self, inode: Option<Arc<KernFSInode>>) {
|
||||||
|
self.inner().kern_inode = inode;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inode(&self) -> Option<Arc<KernFSInode>> {
|
||||||
|
self.inner().kern_inode.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parent(&self) -> Option<Weak<dyn KObject>> {
|
||||||
|
self.inner().parent_kobj.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_parent(&self, parent: Option<Weak<dyn KObject>>) {
|
||||||
|
self.inner().parent_kobj = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn kset(&self) -> Option<Arc<KSet>> {
|
||||||
|
self.inner().kset.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_kset(&self, kset: Option<Arc<KSet>>) {
|
||||||
|
self.inner().kset = kset;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn kobj_type(&self) -> Option<&'static dyn KObjType> {
|
||||||
|
Some(&IrqKObjType)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_kobj_type(&self, _ktype: Option<&'static dyn KObjType>) {}
|
||||||
|
|
||||||
|
fn name(&self) -> String {
|
||||||
|
self.inner().name.clone().unwrap_or_else(|| format!(""))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_name(&self, _name: String) {}
|
||||||
|
|
||||||
|
fn kobj_state(&self) -> RwLockReadGuard<KObjectState> {
|
||||||
|
self.kobj_state.read()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn kobj_state_mut(&self) -> RwLockWriteGuard<KObjectState> {
|
||||||
|
self.kobj_state.write()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_kobj_state(&self, state: KObjectState) {
|
||||||
|
*self.kobj_state_mut() = state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 每个中断的响应动作的描述符
|
||||||
|
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/interrupt.h#118
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct IrqAction {
|
||||||
|
inner: SpinLock<InnerIrqAction>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IrqAction {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn new(
|
||||||
|
irq: IrqNumber,
|
||||||
|
name: String,
|
||||||
|
handler: Option<&'static dyn IrqFlowHandler>,
|
||||||
|
) -> Arc<Self> {
|
||||||
|
let action = IrqAction {
|
||||||
|
inner: SpinLock::new(InnerIrqAction {
|
||||||
|
dev_id: None,
|
||||||
|
handler,
|
||||||
|
thread_fn: None,
|
||||||
|
thread: None,
|
||||||
|
secondary: None,
|
||||||
|
irq,
|
||||||
|
flags: IrqHandleFlags::empty(),
|
||||||
|
name,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
return Arc::new(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct InnerIrqAction {
|
||||||
|
/// cookie to identify the device
|
||||||
|
dev_id: Option<DeviceId>,
|
||||||
|
/// 中断处理程序
|
||||||
|
handler: Option<&'static dyn IrqFlowHandler>,
|
||||||
|
/// interrupt handler function for threaded interrupts
|
||||||
|
thread_fn: Option<&'static dyn IrqFlowHandler>,
|
||||||
|
/// thread pointer for threaded interrupts
|
||||||
|
thread: Option<Arc<ProcessControlBlock>>,
|
||||||
|
/// pointer to secondary irqaction (force threading)
|
||||||
|
secondary: Option<Arc<IrqAction>>,
|
||||||
|
/// 中断号
|
||||||
|
irq: IrqNumber,
|
||||||
|
flags: IrqHandleFlags,
|
||||||
|
/// name of the device
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义IrqFlags位标志
|
||||||
|
bitflags! {
|
||||||
|
/// 这些标志仅由内核在中断处理例程中使用。
|
||||||
|
pub struct IrqHandleFlags: u32 {
|
||||||
|
/// IRQF_SHARED - 允许多个设备共享中断
|
||||||
|
const IRQF_SHARED = 0x00000080;
|
||||||
|
/// IRQF_PROBE_SHARED - 当预期出现共享不匹配时,由调用者设置
|
||||||
|
const IRQF_PROBE_SHARED = 0x00000100;
|
||||||
|
/// IRQF_TIMER - 标记此中断为定时器中断
|
||||||
|
const __IRQF_TIMER = 0x00000200;
|
||||||
|
/// IRQF_PERCPU - 中断是每个CPU的
|
||||||
|
const IRQF_PERCPU = 0x00000400;
|
||||||
|
/// IRQF_NOBALANCING - 将此中断从中断平衡中排除
|
||||||
|
const IRQF_NOBALANCING = 0x00000800;
|
||||||
|
/// IRQF_IRQPOLL - 中断用于轮询(出于性能原因,只有在共享中断中首次注册的中断会被考虑)
|
||||||
|
const IRQF_IRQPOLL = 0x00001000;
|
||||||
|
/// IRQF_ONESHOT - 在硬中断处理程序完成后,不会重新启用中断。由需要在运行线程处理程序之前保持中断线路禁用的线程中断使用。
|
||||||
|
const IRQF_ONESHOT = 0x00002000;
|
||||||
|
/// IRQF_NO_SUSPEND - 在挂起期间不禁用此IRQ。不能保证此中断会从挂起状态唤醒系统。
|
||||||
|
const IRQF_NO_SUSPEND = 0x00004000;
|
||||||
|
/// IRQF_FORCE_RESUME - 即使设置了IRQF_NO_SUSPEND,也强制在恢复时启用它
|
||||||
|
const IRQF_FORCE_RESUME = 0x00008000;
|
||||||
|
/// IRQF_NO_THREAD - 中断不能被线程化
|
||||||
|
const IRQF_NO_THREAD = 0x00010000;
|
||||||
|
/// IRQF_EARLY_RESUME - 在syscore而不是在设备恢复时间早期恢复IRQ。
|
||||||
|
const IRQF_EARLY_RESUME = 0x00020000;
|
||||||
|
/// IRQF_COND_SUSPEND - 如果IRQ与NO_SUSPEND用户共享,则在挂起中断后执行此中断处理程序。对于系统唤醒设备用户,需要在他们的中断处理程序中实现唤醒检测。
|
||||||
|
const IRQF_COND_SUSPEND = 0x00040000;
|
||||||
|
/// IRQF_NO_AUTOEN - 当用户请求时,不会自动启用IRQ或NMI。用户稍后会通过enable_irq()或enable_nmi()显式启用它。
|
||||||
|
const IRQF_NO_AUTOEN = 0x00080000;
|
||||||
|
/// IRQF_NO_DEBUG - 从IPI和类似处理程序的逃逸检测中排除,取决于IRQF_PERCPU。
|
||||||
|
const IRQF_NO_DEBUG = 0x00100000;
|
||||||
|
const IRQF_TIMER = Self::__IRQF_TIMER.bits | Self::IRQF_NO_SUSPEND.bits | Self::IRQF_NO_THREAD.bits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
pub(super) fn early_irq_init() -> Result<(), SystemError> {
|
||||||
|
let irqcnt = CurrentIrqArch::probe_total_irq_num();
|
||||||
|
let mut manager = IrqDescManager::new();
|
||||||
|
for i in 0..irqcnt {
|
||||||
|
let irq_desc = IrqDesc::new(IrqNumber::new(i), None, IrqStatus::empty());
|
||||||
|
manager.insert(IrqNumber::new(i), irq_desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CurrentIrqArch::arch_early_irq_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) struct IrqDescManager {
|
||||||
|
irq_descs: BTreeMap<IrqNumber, Arc<IrqDesc>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IrqDescManager {
|
||||||
|
fn new() -> Self {
|
||||||
|
IrqDescManager {
|
||||||
|
irq_descs: BTreeMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 查找中断描述符
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn lookup(&self, irq: IrqNumber) -> Option<Arc<IrqDesc>> {
|
||||||
|
self.irq_descs.get(&irq).map(|desc| desc.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert(&mut self, irq: IrqNumber, desc: Arc<IrqDesc>) {
|
||||||
|
self.irq_descs.insert(irq, desc);
|
||||||
|
}
|
||||||
|
}
|
@ -145,7 +145,7 @@ pub enum IrqDomainBusToken {
|
|||||||
/// IrqDomain的操作方法
|
/// IrqDomain的操作方法
|
||||||
///
|
///
|
||||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#107
|
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#107
|
||||||
pub trait IrqDomainOps: Debug {
|
pub trait IrqDomainOps: Debug + Send + Sync {
|
||||||
/// 匹配一个中断控制器设备节点到一个主机。
|
/// 匹配一个中断控制器设备节点到一个主机。
|
||||||
fn match_node(
|
fn match_node(
|
||||||
&self,
|
&self,
|
||||||
|
@ -2,13 +2,17 @@ use system_error::SystemError;
|
|||||||
|
|
||||||
use crate::arch::CurrentIrqArch;
|
use crate::arch::CurrentIrqArch;
|
||||||
|
|
||||||
|
pub mod dummychip;
|
||||||
|
pub mod handle;
|
||||||
pub mod init;
|
pub mod init;
|
||||||
pub mod ipi;
|
pub mod ipi;
|
||||||
pub mod irqchip;
|
pub mod irqchip;
|
||||||
pub mod irqdata;
|
pub mod irqdata;
|
||||||
|
pub mod irqdesc;
|
||||||
pub mod irqdomain;
|
pub mod irqdomain;
|
||||||
pub mod msi;
|
pub mod msi;
|
||||||
pub mod softirq;
|
pub mod softirq;
|
||||||
|
pub mod sysfs;
|
||||||
|
|
||||||
/// 中断的架构相关的trait
|
/// 中断的架构相关的trait
|
||||||
pub trait InterruptArch: Send + Sync {
|
pub trait InterruptArch: Send + Sync {
|
||||||
@ -24,6 +28,16 @@ pub trait InterruptArch: Send + Sync {
|
|||||||
/// 保存当前中断状态,并且禁止中断
|
/// 保存当前中断状态,并且禁止中断
|
||||||
unsafe fn save_and_disable_irq() -> IrqFlagsGuard;
|
unsafe fn save_and_disable_irq() -> IrqFlagsGuard;
|
||||||
unsafe fn restore_irq(flags: IrqFlags);
|
unsafe fn restore_irq(flags: IrqFlags);
|
||||||
|
|
||||||
|
/// 检测系统支持的中断总数
|
||||||
|
fn probe_total_irq_num() -> u32;
|
||||||
|
|
||||||
|
fn arch_early_irq_init() -> Result<(), SystemError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 响应未注册的中断
|
||||||
|
fn ack_bad_irq(irq: IrqNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
@ -116,7 +116,7 @@ impl MsiDesc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait MsiDescFunc: Debug {
|
pub trait MsiDescFunc: Debug + Send + Sync {
|
||||||
/// Callback that may be called when the MSI message
|
/// Callback that may be called when the MSI message
|
||||||
/// address or data changes.
|
/// address or data changes.
|
||||||
fn write_msi_msg(&self, data: Arc<dyn MsiDescFuncData>);
|
fn write_msi_msg(&self, data: Arc<dyn MsiDescFuncData>);
|
||||||
|
65
kernel/src/exception/sysfs.rs
Normal file
65
kernel/src/exception/sysfs.rs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
use alloc::sync::Arc;
|
||||||
|
use system_error::SystemError;
|
||||||
|
use unified_init::macros::unified_init;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
driver::base::kobject::{KObjType, KObject, KObjectSysFSOps},
|
||||||
|
filesystem::{
|
||||||
|
sysfs::{Attribute, AttributeGroup, SysFSOps},
|
||||||
|
vfs::syscall::ModeType,
|
||||||
|
},
|
||||||
|
init::initcall::INITCALL_POSTCORE,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// 中断描述符的kobjtype
|
||||||
|
///
|
||||||
|
/// https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/irqdesc.c#280
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(super) struct IrqKObjType;
|
||||||
|
|
||||||
|
impl KObjType for IrqKObjType {
|
||||||
|
fn sysfs_ops(&self) -> Option<&dyn SysFSOps> {
|
||||||
|
Some(&KObjectSysFSOps)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> {
|
||||||
|
Some(&[&IrqAttrGroup])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn release(&self, _kobj: Arc<dyn KObject>) {
|
||||||
|
|
||||||
|
// https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/irqdesc.c#428
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct IrqAttrGroup;
|
||||||
|
|
||||||
|
impl AttributeGroup for IrqAttrGroup {
|
||||||
|
fn name(&self) -> Option<&str> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn attrs(&self) -> &[&'static dyn Attribute] {
|
||||||
|
todo!("irq_attr_group.attrs")
|
||||||
|
// todo: https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/irqdesc.c#268
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_visible(
|
||||||
|
&self,
|
||||||
|
_kobj: Arc<dyn KObject>,
|
||||||
|
attr: &'static dyn Attribute,
|
||||||
|
) -> Option<ModeType> {
|
||||||
|
Some(attr.mode())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 初始化irq模块在sysfs中的目录
|
||||||
|
///
|
||||||
|
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/irqdesc.c#313
|
||||||
|
#[unified_init(INITCALL_POSTCORE)]
|
||||||
|
fn irq_sysfs_init() -> Result<(), SystemError> {
|
||||||
|
// todo!("irq_sysfs_init");
|
||||||
|
kwarn!("Unimplemented: irq_sysfs_init");
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user