mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-09 19:36:47 +00:00
parent
ca318c376b
commit
ce5850adbf
@ -14,7 +14,7 @@ use crate::driver::pci::pci::{
|
||||
get_pci_device_structure_mut, PciDeviceStructure, PciDeviceStructureGeneralDevice, PciError,
|
||||
PCI_DEVICE_LINKEDLIST,
|
||||
};
|
||||
use crate::driver::pci::pci_irq::{IrqCommonMsg, IrqMsg, IrqSpecificMsg, PciInterrupt, IRQ};
|
||||
use crate::driver::pci::pci_irq::{IrqCommonMsg, IrqSpecificMsg, PciInterrupt, PciIrqMsg, IRQ};
|
||||
use crate::include::bindings::bindings::pt_regs;
|
||||
use crate::libs::volatile::{ReadOnly, Volatile, WriteOnly};
|
||||
use crate::net::net_core::poll_ifaces_try_lock_onetime;
|
||||
@ -227,7 +227,7 @@ impl E1000EDevice {
|
||||
let irq_vector = device.irq_vector_mut().unwrap();
|
||||
irq_vector.push(E1000E_RECV_VECTOR);
|
||||
device.irq_init(IRQ::PCI_IRQ_MSI).expect("IRQ Init Failed");
|
||||
let msg = IrqMsg {
|
||||
let msg = PciIrqMsg {
|
||||
irq_common_message: IrqCommonMsg::init_from(
|
||||
0,
|
||||
"E1000E_RECV_IRQ",
|
||||
|
177
kernel/src/driver/open_firmware/device_node.rs
Normal file
177
kernel/src/driver/open_firmware/device_node.rs
Normal file
@ -0,0 +1,177 @@
|
||||
use crate::{
|
||||
driver::base::{
|
||||
kobject::{KObjType, KObject, KObjectState},
|
||||
kset::KSet,
|
||||
},
|
||||
filesystem::{kernfs::KernFSInode, sysfs::BinAttribute},
|
||||
libs::rwlock::{RwLockReadGuard, RwLockWriteGuard},
|
||||
libs::spinlock::SpinLock,
|
||||
};
|
||||
use alloc::{
|
||||
string::String,
|
||||
sync::{Arc, Weak},
|
||||
vec::Vec,
|
||||
};
|
||||
use core::fmt::Debug;
|
||||
|
||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/of.h#51
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub struct DeviceNode {
|
||||
full_name: Option<&'static str>,
|
||||
full_name_allocated: Option<String>,
|
||||
inner: SpinLock<InnerDeviceNode>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
struct InnerDeviceNode {
|
||||
properties: Vec<Property>,
|
||||
parent: Weak<DeviceNode>,
|
||||
children: Vec<Arc<DeviceNode>>,
|
||||
sibling: Option<Weak<DeviceNode>>,
|
||||
private_data: Option<Arc<dyn DeviceNodePrivateData>>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl DeviceNode {
|
||||
pub fn new(
|
||||
full_name: Option<&'static str>,
|
||||
full_name_allocated: Option<String>,
|
||||
) -> Option<Arc<Self>> {
|
||||
if full_name.is_none() && full_name_allocated.is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let x = DeviceNode {
|
||||
full_name,
|
||||
full_name_allocated,
|
||||
inner: SpinLock::new(InnerDeviceNode {
|
||||
properties: Vec::new(),
|
||||
parent: Weak::new(),
|
||||
children: Vec::new(),
|
||||
sibling: None,
|
||||
private_data: None,
|
||||
}),
|
||||
};
|
||||
|
||||
return Some(Arc::new(x));
|
||||
}
|
||||
|
||||
pub fn add_property(&self, prop: Property) {
|
||||
self.inner.lock().properties.push(prop);
|
||||
}
|
||||
|
||||
pub fn properties(&self) -> Vec<Property> {
|
||||
self.inner.lock().properties.clone()
|
||||
}
|
||||
|
||||
pub fn parent(&self) -> Option<Arc<DeviceNode>> {
|
||||
self.inner.lock().parent.upgrade()
|
||||
}
|
||||
|
||||
pub fn set_parent(&self, parent: Arc<DeviceNode>) {
|
||||
self.inner.lock().parent = Arc::downgrade(&parent);
|
||||
}
|
||||
|
||||
pub fn children(&self) -> Vec<Arc<DeviceNode>> {
|
||||
self.inner.lock().children.clone()
|
||||
}
|
||||
|
||||
pub fn add_child(&self, child: Arc<DeviceNode>) {
|
||||
self.inner.lock().children.push(child);
|
||||
}
|
||||
|
||||
pub fn sibling(&self) -> Option<Arc<DeviceNode>> {
|
||||
self.inner.lock().sibling.as_ref().and_then(|s| s.upgrade())
|
||||
}
|
||||
|
||||
pub fn set_sibling(&self, sibling: Arc<DeviceNode>) {
|
||||
self.inner.lock().sibling = Some(Arc::downgrade(&sibling));
|
||||
}
|
||||
|
||||
pub fn private_data(&self) -> Option<Arc<dyn DeviceNodePrivateData>> {
|
||||
self.inner.lock().private_data.clone()
|
||||
}
|
||||
|
||||
pub fn set_private_data(&self, data: Arc<dyn DeviceNodePrivateData>) {
|
||||
self.inner.lock().private_data = Some(data);
|
||||
}
|
||||
}
|
||||
|
||||
pub trait DeviceNodePrivateData: Send + Sync + Debug {}
|
||||
|
||||
impl KObject for DeviceNode {
|
||||
fn as_any_ref(&self) -> &dyn core::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn set_inode(&self, _inode: Option<Arc<KernFSInode>>) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn inode(&self) -> Option<Arc<KernFSInode>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn parent(&self) -> Option<Weak<dyn KObject>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn set_parent(&self, _parent: Option<Weak<dyn KObject>>) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn kset(&self) -> Option<Arc<KSet>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn set_kset(&self, _kset: Option<Arc<KSet>>) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn kobj_type(&self) -> Option<&'static dyn KObjType> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn set_kobj_type(&self, _ktype: Option<&'static dyn KObjType>) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn set_name(&self, _name: String) {}
|
||||
|
||||
fn kobj_state(&self) -> RwLockReadGuard<KObjectState> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn kobj_state_mut(&self) -> RwLockWriteGuard<KObjectState> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn set_kobj_state(&self, _state: KObjectState) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Property {
|
||||
name: String,
|
||||
value: Vec<u8>,
|
||||
bin_attr: Option<Arc<dyn BinAttribute>>,
|
||||
}
|
||||
|
||||
impl Property {
|
||||
#[allow(dead_code)]
|
||||
pub const fn new(name: String, value: Vec<u8>, battr: Option<Arc<dyn BinAttribute>>) -> Self {
|
||||
Property {
|
||||
name,
|
||||
value,
|
||||
bin_attr: battr,
|
||||
}
|
||||
}
|
||||
}
|
@ -1,2 +1,3 @@
|
||||
// #[cfg(target_arch = "riscv64")]
|
||||
pub mod device_node;
|
||||
pub mod fdt;
|
||||
|
@ -70,7 +70,7 @@ pub enum IrqType {
|
||||
|
||||
// PCI设备install中断时需要传递的参数
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct IrqMsg {
|
||||
pub struct PciIrqMsg {
|
||||
pub irq_common_message: IrqCommonMsg,
|
||||
pub irq_specific_message: IrqSpecificMsg,
|
||||
}
|
||||
@ -301,7 +301,7 @@ pub trait PciInterrupt: PciDeviceStructure {
|
||||
/// @param self PCI设备的可变引用
|
||||
/// @param msg PCI设备install中断时需要传递的共同参数
|
||||
/// @return 一切正常返回Ok(0),有错误返回对应错误原因
|
||||
fn irq_install(&mut self, msg: IrqMsg) -> Result<u8, PciError> {
|
||||
fn irq_install(&mut self, msg: PciIrqMsg) -> Result<u8, PciError> {
|
||||
if let Some(irq_vector) = self.irq_vector_mut() {
|
||||
if msg.irq_common_message.irq_index as usize > irq_vector.len() {
|
||||
return Err(PciError::PciIrqError(PciIrqError::InvalidIrqIndex(
|
||||
@ -332,7 +332,7 @@ pub trait PciInterrupt: PciDeviceStructure {
|
||||
/// @param self PCI设备的可变引用
|
||||
/// @param msg PCI设备install中断时需要传递的共同参数
|
||||
/// @return 一切正常返回Ok(0),有错误返回对应错误原因
|
||||
fn msi_install(&mut self, msg: IrqMsg) -> Result<u8, PciError> {
|
||||
fn msi_install(&mut self, msg: PciIrqMsg) -> Result<u8, PciError> {
|
||||
if let Some(irq_type) = self.irq_type_mut() {
|
||||
match *irq_type {
|
||||
IrqType::Msi {
|
||||
@ -482,7 +482,7 @@ pub trait PciInterrupt: PciDeviceStructure {
|
||||
/// @param self PCI设备的可变引用
|
||||
/// @param msg PCI设备install中断时需要传递的共同参数
|
||||
/// @return 一切正常返回Ok(0),有错误返回对应错误原因
|
||||
fn msix_install(&mut self, msg: IrqMsg) -> Result<u8, PciError> {
|
||||
fn msix_install(&mut self, msg: PciIrqMsg) -> Result<u8, PciError> {
|
||||
if let Some(irq_type) = self.irq_type_mut() {
|
||||
match *irq_type {
|
||||
IrqType::Msix {
|
||||
|
@ -5,7 +5,7 @@ use crate::driver::pci::pci::{
|
||||
PciStandardDeviceBar, PCI_CAP_ID_VNDR,
|
||||
};
|
||||
|
||||
use crate::driver::pci::pci_irq::{IrqCommonMsg, IrqMsg, IrqSpecificMsg, PciInterrupt, IRQ};
|
||||
use crate::driver::pci::pci_irq::{IrqCommonMsg, IrqSpecificMsg, PciInterrupt, PciIrqMsg, IRQ};
|
||||
use crate::include::bindings::bindings::pt_regs;
|
||||
use crate::libs::volatile::{
|
||||
volread, volwrite, ReadOnly, Volatile, VolatileReadable, VolatileWritable, WriteOnly,
|
||||
@ -133,7 +133,7 @@ impl PciTransport {
|
||||
.irq_init(IRQ::PCI_IRQ_MSIX)
|
||||
.expect("IRQ init failed");
|
||||
// 中断相关信息
|
||||
let msg = IrqMsg {
|
||||
let msg = PciIrqMsg {
|
||||
irq_common_message: IrqCommonMsg::init_from(
|
||||
0,
|
||||
"Virtio_Recv_IRQ",
|
||||
|
239
kernel/src/exception/irqchip.rs
Normal file
239
kernel/src/exception/irqchip.rs
Normal file
@ -0,0 +1,239 @@
|
||||
use core::{any::Any, fmt::Debug};
|
||||
|
||||
use alloc::{
|
||||
sync::{Arc, Weak},
|
||||
vec::Vec,
|
||||
};
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{libs::spinlock::SpinLock, mm::VirtAddr};
|
||||
|
||||
use super::{
|
||||
irqdata::{IrqData, IrqLineStatus},
|
||||
irqdomain::IrqDomain,
|
||||
msi::MsiMsg,
|
||||
};
|
||||
|
||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#506
|
||||
pub trait IrqChip: Sync + Send + Any + Debug {
|
||||
fn name(&self) -> &'static str;
|
||||
/// start up the interrupt (defaults to ->enable if ENOSYS)
|
||||
fn irq_startup(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||
Err(SystemError::ENOSYS)
|
||||
}
|
||||
|
||||
/// shut down the interrupt (defaults to ->disable if ENOSYS)
|
||||
fn irq_shutdown(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||
Err(SystemError::ENOSYS)
|
||||
}
|
||||
|
||||
/// enable the interrupt
|
||||
///
|
||||
/// (defaults to ->unmask if ENOSYS)
|
||||
fn irq_enable(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||
Err(SystemError::ENOSYS)
|
||||
}
|
||||
|
||||
/// disable the interrupt
|
||||
fn irq_disable(&self, irq: &Arc<IrqData>);
|
||||
|
||||
/// start of a new interrupt
|
||||
fn irq_ack(&self, irq: &Arc<IrqData>);
|
||||
|
||||
/// mask an interrupt source
|
||||
fn irq_mask(&self, irq: &Arc<IrqData>);
|
||||
/// ack and mask an interrupt source
|
||||
fn irq_mask_ack(&self, irq: &Arc<IrqData>);
|
||||
/// unmask an interrupt source
|
||||
fn irq_unmask(&self, irq: &Arc<IrqData>);
|
||||
/// end of interrupt
|
||||
fn irq_eoi(&self, irq: &Arc<IrqData>);
|
||||
|
||||
// todo: set affinity
|
||||
|
||||
/// retrigger an IRQ to the CPU
|
||||
fn retrigger(&self, irq: &Arc<IrqData>);
|
||||
|
||||
/// set the flow type of an interrupt
|
||||
///
|
||||
/// flow_type: the flow type to set
|
||||
///
|
||||
fn irq_set_type(
|
||||
&self,
|
||||
_irq: &Arc<IrqData>,
|
||||
_flow_type: IrqLineStatus,
|
||||
) -> Result<(), SystemError> {
|
||||
Err(SystemError::ENOSYS)
|
||||
}
|
||||
|
||||
/// enable/disable power management wake-on of an interrupt
|
||||
fn irq_set_wake(&self, _irq: &Arc<IrqData>, _on: bool) -> Result<(), SystemError> {
|
||||
Err(SystemError::ENOSYS)
|
||||
}
|
||||
|
||||
/// function to lock access to slow bus (i2c) chips
|
||||
fn irq_bus_lock(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// function to sync and unlock slow bus (i2c) chips
|
||||
fn irq_bus_sync_unlock(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// function called from core code on suspend once per
|
||||
/// chip, when one or more interrupts are installed
|
||||
fn irq_suspend(&self, irq: &Arc<IrqData>);
|
||||
|
||||
/// function called from core code on resume once per chip,
|
||||
/// when one ore more interrupts are installed
|
||||
fn irq_resume(&self, irq: &Arc<IrqData>);
|
||||
|
||||
/// function called from core code on shutdown once per chip
|
||||
fn irq_pm_shutdown(&self, irq: &Arc<IrqData>);
|
||||
|
||||
/// Optional function to set irq_data.mask for special cases
|
||||
fn irq_calc_mask(&self, _irq: &Arc<IrqData>) {}
|
||||
|
||||
// todo: print chip
|
||||
|
||||
/// optional to request resources before calling
|
||||
/// any other callback related to this irq
|
||||
fn irq_request_resources(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// optional to release resources acquired with
|
||||
/// irq_request_resources
|
||||
fn irq_release_resources(&self, _irq: &Arc<IrqData>) {}
|
||||
|
||||
/// optional to compose message content for MSI
|
||||
fn irq_compose_msi_msg(&self, _irq: &Arc<IrqData>, _msg: &mut MsiMsg) {}
|
||||
|
||||
/// optional to write message content for MSI
|
||||
fn irq_write_msi_msg(&self, _irq: &Arc<IrqData>, _msg: &MsiMsg) {}
|
||||
|
||||
/// return the internal state of an interrupt
|
||||
fn irqchip_state(
|
||||
&self,
|
||||
_irq: &Arc<IrqData>,
|
||||
_which: IrqChipState,
|
||||
) -> Result<bool, SystemError> {
|
||||
Err(SystemError::ENOSYS)
|
||||
}
|
||||
|
||||
/// set the internal state of an interrupt
|
||||
fn set_irqchip_state(
|
||||
&self,
|
||||
_irq: &Arc<IrqData>,
|
||||
_which: IrqChipState,
|
||||
_state: bool,
|
||||
) -> Result<(), SystemError> {
|
||||
Err(SystemError::ENOSYS)
|
||||
}
|
||||
|
||||
// todo: set vcpu affinity
|
||||
|
||||
/// send a single IPI to destination cpus
|
||||
fn send_single_ipi(&self, irq: &Arc<IrqData>, cpu: u32);
|
||||
|
||||
// todo: send ipi with cpu mask
|
||||
|
||||
/// function called from core code before enabling an NMI
|
||||
fn irq_nmi_setup(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||
Err(SystemError::ENOSYS)
|
||||
}
|
||||
|
||||
/// function called from core code after disabling an NMI
|
||||
fn irq_nmi_teardown(&self, irq: &Arc<IrqData>);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum IrqChipState {
|
||||
/// Is the interrupt pending?
|
||||
Pending,
|
||||
/// Is the interrupt in progress?
|
||||
Active,
|
||||
/// Is the interrupt masked?
|
||||
Masked,
|
||||
/// Is Irq line high?
|
||||
LineLevel,
|
||||
}
|
||||
|
||||
pub trait IrqChipData: Sync + Send + Any + Debug {}
|
||||
|
||||
bitflags! {
|
||||
/// 定义 IrqGcFlags 位标志
|
||||
pub struct IrqGcFlags: u32 {
|
||||
/// 通过读取mask reg来初始化mask_cache
|
||||
const IRQ_GC_INIT_MASK_CACHE = 1 << 0;
|
||||
/// 对于需要在父irq上调用irq_set_wake()的irq芯片, 将irqs的锁类设置为嵌套。Usually GPIO implementations
|
||||
const IRQ_GC_INIT_NESTED_LOCK = 1 << 1;
|
||||
/// Mask cache是芯片类型私有的
|
||||
const IRQ_GC_MASK_CACHE_PER_TYPE = 1 << 2;
|
||||
/// 不计算irqData->mask
|
||||
const IRQ_GC_NO_MASK = 1 << 3;
|
||||
/// 使用大端字节序的寄存器访问(默认:小端LE)
|
||||
const IRQ_GC_BE_IO = 1 << 4;
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub struct IrqChipGeneric {
|
||||
inner: SpinLock<InnerIrqChipGeneric>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
struct InnerIrqChipGeneric {
|
||||
/// Register base address
|
||||
reg_base: VirtAddr,
|
||||
ops: &'static dyn IrqChipGenericOps,
|
||||
/// Interrupt base num for this chip
|
||||
irq_base: u32,
|
||||
/// Number of interrupts handled by this chip
|
||||
irq_cnt: u32,
|
||||
/// Cached mask register shared between all chip types
|
||||
mask_cache: u32,
|
||||
/// Cached type register
|
||||
type_cache: u32,
|
||||
/// Cached polarity register
|
||||
polarity_cache: u32,
|
||||
/// Interrupt can wakeup from suspend
|
||||
wake_enabled: bool,
|
||||
/// Interrupt is marked as an wakeup from suspend source
|
||||
wake_active: bool,
|
||||
/// Number of available irq_chip_type instances (usually 1)
|
||||
num_chip_type: u32,
|
||||
private_data: Option<Arc<dyn IrqChipGenericPrivateData>>,
|
||||
installed: u64,
|
||||
unused: u64,
|
||||
domain: Weak<IrqDomain>,
|
||||
chip_types: Vec<IrqChipType>,
|
||||
}
|
||||
|
||||
pub trait IrqChipGenericOps: Debug {
|
||||
/// Alternate I/O accessor (defaults to readl if NULL)
|
||||
unsafe fn reg_readl(&self, addr: VirtAddr) -> u32;
|
||||
|
||||
/// Alternate I/O accessor (defaults to writel if NULL)
|
||||
unsafe fn reg_writel(&self, addr: VirtAddr, val: u32);
|
||||
|
||||
/// Function called from core code on suspend once per
|
||||
/// chip; can be useful instead of irq_chip::suspend to
|
||||
/// handle chip details even when no interrupts are in use
|
||||
fn suspend(&self, gc: &Arc<IrqChipGeneric>);
|
||||
/// Function called from core code on resume once per chip;
|
||||
/// can be useful instead of irq_chip::resume to handle chip
|
||||
/// details even when no interrupts are in use
|
||||
fn resume(&self, gc: &Arc<IrqChipGeneric>);
|
||||
}
|
||||
|
||||
pub trait IrqChipGenericPrivateData: Sync + Send + Any + Debug {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IrqChipType {
|
||||
// todo https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#1024
|
||||
}
|
332
kernel/src/exception/irqdata.rs
Normal file
332
kernel/src/exception/irqdata.rs
Normal file
@ -0,0 +1,332 @@
|
||||
use core::{any::Any, fmt::Debug};
|
||||
|
||||
use alloc::sync::{Arc, Weak};
|
||||
|
||||
use crate::libs::spinlock::SpinLock;
|
||||
|
||||
use super::{
|
||||
irqchip::{IrqChip, IrqChipData},
|
||||
irqdomain::IrqDomain,
|
||||
msi::MsiDesc,
|
||||
HardwareIrqNumber, IrqNumber,
|
||||
};
|
||||
|
||||
/// per irq chip data passed down to chip functions
|
||||
///
|
||||
/// 该结构体用于表示每个Irq的私有数据,且与具体的中断芯片绑定
|
||||
///
|
||||
/// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#179
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub struct IrqData {
|
||||
/// 中断号, 用于表示软件逻辑视角的中断号,全局唯一
|
||||
irq: IrqNumber,
|
||||
/// 硬件中断号, 用于表示在某个IrqDomain中的中断号
|
||||
hwirq: HardwareIrqNumber,
|
||||
/// 涉及的所有irqchip之间共享的数据
|
||||
common_data: Arc<IrqCommonData>,
|
||||
/// 绑定到的中断芯片
|
||||
chip: Arc<dyn IrqChip>,
|
||||
/// 中断芯片的私有数据(与当前irq相关)
|
||||
chip_data: Arc<dyn IrqChipData>,
|
||||
/// 中断域
|
||||
domain: Arc<IrqDomain>,
|
||||
/// 中断的父中断(如果具有中断域继承的话)
|
||||
parent_data: Option<Weak<IrqData>>,
|
||||
}
|
||||
|
||||
/// per irq data shared by all irqchips
|
||||
///
|
||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#147
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub struct IrqCommonData {
|
||||
inner: SpinLock<InnerIrqCommonData>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
struct InnerIrqCommonData {
|
||||
/// status information for irq chip functions.
|
||||
state: IrqStatus,
|
||||
/// per-IRQ data for the irq_chip methods
|
||||
handler_data: Option<Arc<dyn IrqHandlerData>>,
|
||||
msi_desc: Option<Arc<MsiDesc>>,
|
||||
// todo: affinity
|
||||
}
|
||||
|
||||
pub trait IrqHandlerData: Send + Sync + Any + Debug {}
|
||||
|
||||
bitflags! {
|
||||
/// 中断线状态
|
||||
/// https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h?fi=IRQ_TYPE_PROBE#77
|
||||
pub struct IrqLineStatus: u32 {
|
||||
/// 默认,未指明类型
|
||||
const IRQ_TYPE_NONE = 0x00000000;
|
||||
/// 上升沿触发
|
||||
const IRQ_TYPE_EDGE_RISING = 0x00000001;
|
||||
/// 下降沿触发
|
||||
const IRQ_TYPE_EDGE_FALLING = 0x00000002;
|
||||
/// 上升沿和下降沿触发
|
||||
const IRQ_TYPE_EDGE_BOTH = Self::IRQ_TYPE_EDGE_RISING.bits | Self::IRQ_TYPE_EDGE_FALLING.bits;
|
||||
/// 高电平触发
|
||||
const IRQ_TYPE_LEVEL_HIGH = 0x00000004;
|
||||
/// 低电平触发
|
||||
const IRQ_TYPE_LEVEL_LOW = 0x00000008;
|
||||
/// 过滤掉电平位的掩码
|
||||
const IRQ_TYPE_LEVEL_MASK = Self::IRQ_TYPE_LEVEL_LOW.bits | Self::IRQ_TYPE_LEVEL_HIGH.bits;
|
||||
/// 上述位掩码的掩码
|
||||
const IRQ_TYPE_SENSE_MASK = 0x0000000f;
|
||||
/// 某些PICs使用此类型要求 `IrqChip::irq_set_type()` 设置硬件到一个合理的默认值
|
||||
/// (由irqdomain的map()回调使用,以便为新分配的描述符同步硬件状态和软件标志位)。
|
||||
const IRQ_TYPE_DEFAULT = Self::IRQ_TYPE_SENSE_MASK.bits;
|
||||
|
||||
/// 特定于探测的过程中的特殊标志
|
||||
const IRQ_TYPE_PROBE = 0x00000010;
|
||||
|
||||
/// 中断是电平类型。当上述触发位通过`IrqChip::irq_set_type()` 修改时,也会在代码中更新
|
||||
const IRQ_LEVEL = 1 << 8;
|
||||
/// 标记一个PER_CPU的中断。将保护其免受亲和性设置的影响
|
||||
const IRQ_PER_CPU = 1 << 9;
|
||||
/// 中断不能被自动探测
|
||||
const IRQ_NOPROBE = 1 << 10;
|
||||
/// 中断不能通过request_irq()请求
|
||||
const IRQ_NOREQUEST = 1 << 11;
|
||||
/// 中断在request/setup_irq()中不会自动启用
|
||||
const IRQ_NOAUTOEN = 1 << 12;
|
||||
/// 中断不能被平衡(亲和性设置)
|
||||
const IRQ_NO_BALANCING = 1 << 13;
|
||||
/// 中断可以从进程上下文中迁移
|
||||
const IRQ_MOVE_PCNTXT = 1 << 14;
|
||||
/// 中断嵌套在另一个线程中
|
||||
const IRQ_NESTED_THREAD = 1 << 15;
|
||||
/// 中断不能被线程化
|
||||
const IRQ_NOTHREAD = 1 << 16;
|
||||
/// Dev_id是一个per-CPU变量
|
||||
const IRQ_PER_CPU_DEVID = 1 << 17;
|
||||
/// 总是由另一个中断轮询。将其从错误的中断检测机制和核心侧轮询中排除
|
||||
const IRQ_IS_POLLED = 1 << 18;
|
||||
/// 禁用延迟的中断禁用 (Disable lazy irq disable)
|
||||
const IRQ_DISABLE_UNLAZY = 1 << 19;
|
||||
/// 在/proc/interrupts中不显示
|
||||
const IRQ_HIDDEN = 1 << 20;
|
||||
/// 从note_interrupt()调试中排除
|
||||
const IRQ_NO_DEBUG = 1 << 21;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
bitflags! {
|
||||
/// 中断状态(存储在IrqCommonData)
|
||||
///
|
||||
/// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#227
|
||||
pub struct IrqStatus: u32 {
|
||||
/// 触发类型位的掩码
|
||||
const IRQD_TRIGGER_MASK = 0xf;
|
||||
/// 亲和性设置待处理
|
||||
const IRQD_SETAFFINITY_PENDING = 1 << 8;
|
||||
/// 中断已激活
|
||||
const IRQD_ACTIVATED = 1 << 9;
|
||||
/// 对此IRQ禁用平衡
|
||||
const IRQD_NO_BALANCING = 1 << 10;
|
||||
/// 中断是每个CPU特定的
|
||||
const IRQD_PER_CPU = 1 << 11;
|
||||
/// 中断亲和性已设置
|
||||
const IRQD_AFFINITY_SET = 1 << 12;
|
||||
/// 中断是电平触发
|
||||
const IRQD_LEVEL = 1 << 13;
|
||||
/// 中断配置为从挂起状态唤醒
|
||||
const IRQD_WAKEUP_STATE = 1 << 14;
|
||||
/// 中断可以在进程上下文中移动
|
||||
const IRQD_MOVE_PCNTXT = 1 << 15;
|
||||
/// 中断被禁用
|
||||
const IRQD_IRQ_DISABLED = 1 << 16;
|
||||
/// 中断被屏蔽
|
||||
const IRQD_IRQ_MASKED = 1 << 17;
|
||||
/// 中断正在处理中
|
||||
const IRQD_IRQ_INPROGRESS = 1 << 18;
|
||||
/// 唤醒模式已准备就绪
|
||||
const IRQD_WAKEUP_ARMED = 1 << 19;
|
||||
/// 中断被转发到一个虚拟CPU
|
||||
const IRQD_FORWARDED_TO_VCPU = 1 << 20;
|
||||
/// 亲和性由内核自动管理
|
||||
const IRQD_AFFINITY_MANAGED = 1 << 21;
|
||||
/// 中断已启动
|
||||
const IRQD_IRQ_STARTED = 1 << 22;
|
||||
/// 由于空亲和性掩码而关闭的中断。仅适用于亲和性管理的中断。
|
||||
const IRQD_MANAGED_SHUTDOWN = 1 << 23;
|
||||
/// IRQ只允许单个亲和性目标
|
||||
const IRQD_SINGLE_TARGET = 1 << 24;
|
||||
/// 预期的触发器已设置
|
||||
const IRQD_DEFAULT_TRIGGER_SET = 1 << 25;
|
||||
/// 可以使用保留模式
|
||||
const IRQD_CAN_RESERVE = 1 << 26;
|
||||
/// Non-maskable MSI quirk for affinity change required
|
||||
const IRQD_MSI_NOMASK_QUIRK = 1 << 27;
|
||||
/// 强制要求`handle_irq_()`只能在真实的中断上下文中调用
|
||||
const IRQD_HANDLE_ENFORCE_IRQCTX = 1 << 28;
|
||||
/// 激活时设置亲和性。在禁用时不要调用irq_chip::irq_set_affinity()。
|
||||
const IRQD_AFFINITY_ON_ACTIVATE = 1 << 29;
|
||||
/// 如果irqpm具有标志 IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND,则在挂起时中断被启用。
|
||||
const IRQD_IRQ_ENABLED_ON_SUSPEND = 1 << 30;
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl IrqStatus {
|
||||
pub const fn is_set_affinity_pending(&self) -> bool {
|
||||
self.contains(Self::IRQD_SETAFFINITY_PENDING)
|
||||
}
|
||||
|
||||
pub const fn is_per_cpu(&self) -> bool {
|
||||
self.contains(Self::IRQD_PER_CPU)
|
||||
}
|
||||
|
||||
pub const fn can_balance(&self) -> bool {
|
||||
!((self.bits & (Self::IRQD_PER_CPU.bits | Self::IRQD_NO_BALANCING.bits)) != 0)
|
||||
}
|
||||
|
||||
pub const fn affinity_was_set(&self) -> bool {
|
||||
self.contains(Self::IRQD_AFFINITY_SET)
|
||||
}
|
||||
|
||||
pub fn mark_affinity_set(&mut self) {
|
||||
self.insert(Self::IRQD_AFFINITY_SET);
|
||||
}
|
||||
|
||||
pub const fn trigger_type_was_set(&self) -> bool {
|
||||
self.contains(Self::IRQD_DEFAULT_TRIGGER_SET)
|
||||
}
|
||||
|
||||
pub fn mark_trigger_type_set(&mut self) {
|
||||
self.insert(Self::IRQD_DEFAULT_TRIGGER_SET);
|
||||
}
|
||||
|
||||
pub const fn trigger_type(&self) -> IrqLineStatus {
|
||||
IrqLineStatus::from_bits_truncate(self.bits & Self::IRQD_TRIGGER_MASK.bits)
|
||||
}
|
||||
|
||||
/// Must only be called inside irq_chip.irq_set_type() functions or
|
||||
/// from the DT/ACPI setup code.
|
||||
pub const fn set_trigger_type(&mut self, trigger: IrqLineStatus) {
|
||||
self.bits &= !Self::IRQD_TRIGGER_MASK.bits;
|
||||
self.bits |= trigger.bits & Self::IRQD_TRIGGER_MASK.bits;
|
||||
|
||||
self.bits |= Self::IRQD_DEFAULT_TRIGGER_SET.bits;
|
||||
}
|
||||
|
||||
pub const fn is_level_type(&self) -> bool {
|
||||
self.contains(Self::IRQD_LEVEL)
|
||||
}
|
||||
|
||||
/// Must only be called of irqchip.irq_set_affinity() or low level
|
||||
/// hierarchy domain allocation functions.
|
||||
pub fn set_single_target(&mut self) {
|
||||
self.insert(Self::IRQD_SINGLE_TARGET);
|
||||
}
|
||||
|
||||
pub const fn is_single_target(&self) -> bool {
|
||||
self.contains(Self::IRQD_SINGLE_TARGET)
|
||||
}
|
||||
|
||||
pub fn set_handle_enforce_irqctx(&mut self) {
|
||||
self.insert(Self::IRQD_HANDLE_ENFORCE_IRQCTX);
|
||||
}
|
||||
|
||||
pub const fn is_handle_enforce_irqctx(&self) -> bool {
|
||||
self.contains(Self::IRQD_HANDLE_ENFORCE_IRQCTX)
|
||||
}
|
||||
|
||||
pub const fn is_enabled_on_suspend(&self) -> bool {
|
||||
self.contains(Self::IRQD_IRQ_ENABLED_ON_SUSPEND)
|
||||
}
|
||||
|
||||
pub const fn is_wakeup_set(&self) -> bool {
|
||||
self.contains(Self::IRQD_WAKEUP_STATE)
|
||||
}
|
||||
|
||||
pub const fn can_move_in_process_context(&self) -> bool {
|
||||
self.contains(Self::IRQD_MOVE_PCNTXT)
|
||||
}
|
||||
|
||||
pub const fn is_irq_disabled(&self) -> bool {
|
||||
self.contains(Self::IRQD_IRQ_DISABLED)
|
||||
}
|
||||
|
||||
pub const fn is_irq_masked(&self) -> bool {
|
||||
self.contains(Self::IRQD_IRQ_MASKED)
|
||||
}
|
||||
|
||||
pub const fn is_irq_in_progress(&self) -> bool {
|
||||
self.contains(Self::IRQD_IRQ_INPROGRESS)
|
||||
}
|
||||
|
||||
pub const fn is_wakeup_armed(&self) -> bool {
|
||||
self.contains(Self::IRQD_WAKEUP_ARMED)
|
||||
}
|
||||
|
||||
pub const fn is_forwarded_to_vcpu(&self) -> bool {
|
||||
self.contains(Self::IRQD_FORWARDED_TO_VCPU)
|
||||
}
|
||||
|
||||
pub fn set_forwarded_to_vcpu(&mut self) {
|
||||
self.insert(Self::IRQD_FORWARDED_TO_VCPU);
|
||||
}
|
||||
|
||||
pub const fn is_affinity_managed(&self) -> bool {
|
||||
self.contains(Self::IRQD_AFFINITY_MANAGED)
|
||||
}
|
||||
|
||||
pub const fn is_activated(&self) -> bool {
|
||||
self.contains(Self::IRQD_ACTIVATED)
|
||||
}
|
||||
|
||||
pub fn set_activated(&mut self) {
|
||||
self.insert(Self::IRQD_ACTIVATED);
|
||||
}
|
||||
|
||||
pub fn clear_activated(&mut self) {
|
||||
self.remove(Self::IRQD_ACTIVATED);
|
||||
}
|
||||
|
||||
pub const fn is_started(&self) -> bool {
|
||||
self.contains(Self::IRQD_IRQ_STARTED)
|
||||
}
|
||||
|
||||
pub const fn is_managed_and_shutdown(&self) -> bool {
|
||||
self.contains(Self::IRQD_MANAGED_SHUTDOWN)
|
||||
}
|
||||
|
||||
pub fn set_can_reserve(&mut self) {
|
||||
self.insert(Self::IRQD_CAN_RESERVE);
|
||||
}
|
||||
|
||||
pub const fn can_reserve(&self) -> bool {
|
||||
self.contains(Self::IRQD_CAN_RESERVE)
|
||||
}
|
||||
|
||||
pub fn clear_can_reserve(&mut self) {
|
||||
self.remove(Self::IRQD_CAN_RESERVE);
|
||||
}
|
||||
|
||||
pub fn set_msi_nomask_quirk(&mut self) {
|
||||
self.insert(Self::IRQD_MSI_NOMASK_QUIRK);
|
||||
}
|
||||
|
||||
pub fn clear_msi_nomask_quirk(&mut self) {
|
||||
self.remove(Self::IRQD_MSI_NOMASK_QUIRK);
|
||||
}
|
||||
|
||||
pub const fn is_msi_nomask_quirk(&self) -> bool {
|
||||
self.contains(Self::IRQD_MSI_NOMASK_QUIRK)
|
||||
}
|
||||
|
||||
pub fn set_affinity_on_activate(&mut self) {
|
||||
self.insert(Self::IRQD_AFFINITY_ON_ACTIVATE);
|
||||
}
|
||||
|
||||
pub const fn is_affinity_on_activate(&self) -> bool {
|
||||
self.contains(Self::IRQD_AFFINITY_ON_ACTIVATE)
|
||||
}
|
||||
}
|
184
kernel/src/exception/irqdomain.rs
Normal file
184
kernel/src/exception/irqdomain.rs
Normal file
@ -0,0 +1,184 @@
|
||||
use core::fmt::Debug;
|
||||
|
||||
use alloc::{
|
||||
string::String,
|
||||
sync::{Arc, Weak},
|
||||
vec::Vec,
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
driver::{base::device::Device, open_firmware::device_node::DeviceNode},
|
||||
libs::{rwlock::RwLock, spinlock::SpinLock},
|
||||
};
|
||||
|
||||
use super::{
|
||||
irqchip::{IrqChipGeneric, IrqGcFlags},
|
||||
HardwareIrqNumber, IrqNumber,
|
||||
};
|
||||
|
||||
/// 中断域
|
||||
///
|
||||
/// 用于把硬件中断号翻译为软件中断号的映射的对象
|
||||
///
|
||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#164
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub struct IrqDomain {
|
||||
/// 中断域的名字 (二选一)
|
||||
name: Option<&'static str>,
|
||||
allocated_name: Option<String>,
|
||||
/// 中断域的操作
|
||||
ops: &'static dyn IrqDomainOps,
|
||||
inner: SpinLock<InnerIrqDomain>,
|
||||
/// 中断号反向映射
|
||||
revmap: RwLock<IrqDomainRevMap>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
struct InnerIrqDomain {
|
||||
/// host per irq_domain flags
|
||||
flags: IrqDomainFlags,
|
||||
/// The number of mapped interrupts
|
||||
mapcount: u32,
|
||||
bus_token: IrqDomainBusToken,
|
||||
/// 指向 generic chip 列表的指针。
|
||||
/// 有一个辅助函数用于为中断控制器驱动程序设置一个或
|
||||
/// 多个 generic chip,该函数使用此指针并依赖于 generic chip 库。
|
||||
generic_chip: Option<Arc<IrqDomainChipGeneric>>,
|
||||
/// Pointer to a device that the domain represent, and that will be
|
||||
/// used for power management purposes.
|
||||
device: Option<Arc<dyn Device>>,
|
||||
/// Pointer to parent irq_domain to support hierarchy irq_domains
|
||||
parent: Option<Weak<IrqDomain>>,
|
||||
}
|
||||
|
||||
impl IrqDomain {
|
||||
#[allow(dead_code)]
|
||||
pub fn new(
|
||||
name: Option<&'static str>,
|
||||
allocated_name: Option<String>,
|
||||
ops: &'static dyn IrqDomainOps,
|
||||
flags: IrqDomainFlags,
|
||||
bus_token: IrqDomainBusToken,
|
||||
) -> Option<Arc<Self>> {
|
||||
if name.is_none() && allocated_name.is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let x = IrqDomain {
|
||||
name,
|
||||
allocated_name,
|
||||
ops,
|
||||
inner: SpinLock::new(InnerIrqDomain {
|
||||
flags,
|
||||
mapcount: 0,
|
||||
bus_token,
|
||||
generic_chip: None,
|
||||
device: None,
|
||||
parent: None,
|
||||
}),
|
||||
revmap: RwLock::new(IrqDomainRevMap {
|
||||
map: HashMap::new(),
|
||||
hwirq_max: HardwareIrqNumber::new(0),
|
||||
}),
|
||||
};
|
||||
|
||||
return Some(Arc::new(x));
|
||||
}
|
||||
}
|
||||
|
||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#190
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
struct IrqDomainRevMap {
|
||||
map: HashMap<HardwareIrqNumber, IrqNumber>,
|
||||
hwirq_max: HardwareIrqNumber,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
pub struct IrqDomainFlags: u32 {
|
||||
/// Irq domain is hierarchical
|
||||
const HIERARCHY = (1 << 0);
|
||||
/// Irq domain name was allocated dynamically
|
||||
const NAME_ALLOCATED = (1 << 1);
|
||||
/// Irq domain is an IPI domain with virq per cpu
|
||||
const IPI_PER_CPU = (1 << 2);
|
||||
/// Irq domain is an IPI domain with single virq
|
||||
const IPI_SINGLE = (1 << 3);
|
||||
/// Irq domain implements MSIs
|
||||
const MSI = (1 << 4);
|
||||
/// Irq domain implements MSI remapping
|
||||
const MSI_REMAP = (1 << 5);
|
||||
/// Quirk to handle MSI implementations which do not provide masking
|
||||
const MSI_NOMASK_QUIRK = (1 << 6);
|
||||
/// Irq domain doesn't translate anything
|
||||
const NO_MAP = (1 << 7);
|
||||
/// Flags starting from IRQ_DOMAIN_FLAG_NONCORE are reserved
|
||||
/// for implementation specific purposes and ignored by the core code
|
||||
const NONCORE = (1 << 16);
|
||||
}
|
||||
}
|
||||
|
||||
/// 如果多个域有相同的设备节点,但服务于不同的目的(例如,一个域用于PCI/MSI,另一个用于有线IRQs),
|
||||
/// 它们可以使用特定于总线的token进行区分。预计大多数域只会携带`DomainBusAny`。
|
||||
///
|
||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#78
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum IrqDomainBusToken {
|
||||
Any = 0,
|
||||
Wired,
|
||||
GenericMsi,
|
||||
PciMsi,
|
||||
PlatformMsi,
|
||||
Nexus,
|
||||
Ipi,
|
||||
FslMcMsi,
|
||||
TiSciIntaMsi,
|
||||
Wakeup,
|
||||
VmdMsi,
|
||||
}
|
||||
|
||||
/// IrqDomain的操作方法
|
||||
///
|
||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#107
|
||||
pub trait IrqDomainOps: Debug {
|
||||
/// 匹配一个中断控制器设备节点到一个主机。
|
||||
fn match_node(
|
||||
&self,
|
||||
irq_domain: &Arc<IrqDomain>,
|
||||
device_node: &Arc<DeviceNode>,
|
||||
bus_token: IrqDomainBusToken,
|
||||
) -> bool;
|
||||
|
||||
/// 创建或更新一个虚拟中断号与一个硬件中断号之间的映射。
|
||||
/// 对于给定的映射,这只会被调用一次。
|
||||
fn map(
|
||||
&self,
|
||||
irq_domain: &Arc<IrqDomain>,
|
||||
hwirq: HardwareIrqNumber,
|
||||
virq: IrqNumber,
|
||||
) -> Result<(), SystemError>;
|
||||
|
||||
/// 删除一个虚拟中断号与一个硬件中断号之间的映射。
|
||||
fn unmap(&self, irq_domain: &Arc<IrqDomain>, virq: IrqNumber);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub struct IrqDomainChipGeneric {
|
||||
inner: SpinLock<InnerIrqDomainChipGeneric>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
struct InnerIrqDomainChipGeneric {
|
||||
irqs_per_chip: u32,
|
||||
flags_to_clear: IrqGcFlags,
|
||||
flags_to_set: IrqGcFlags,
|
||||
gc_flags: IrqGcFlags,
|
||||
gc: Vec<Arc<IrqChipGeneric>>,
|
||||
}
|
@ -4,6 +4,10 @@ use crate::arch::CurrentIrqArch;
|
||||
|
||||
pub mod init;
|
||||
pub mod ipi;
|
||||
pub mod irqchip;
|
||||
pub mod irqdata;
|
||||
pub mod irqdomain;
|
||||
pub mod msi;
|
||||
pub mod softirq;
|
||||
|
||||
/// 中断的架构相关的trait
|
||||
@ -77,3 +81,11 @@ impl Drop for IrqFlagsGuard {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 定义中断号结构体
|
||||
// 用于表示软件逻辑视角的中断号,全局唯一
|
||||
int_like!(IrqNumber, u32);
|
||||
|
||||
// 硬件中断号
|
||||
// 用于表示在某个IrqDomain中的中断号
|
||||
int_like!(HardwareIrqNumber, u32);
|
||||
|
126
kernel/src/exception/msi.rs
Normal file
126
kernel/src/exception/msi.rs
Normal file
@ -0,0 +1,126 @@
|
||||
use core::{any::Any, fmt::Debug};
|
||||
|
||||
use alloc::sync::Arc;
|
||||
|
||||
use crate::{
|
||||
driver::{base::device::Device, pci::pci_irq::PciIrqMsg},
|
||||
filesystem::sysfs::Attribute,
|
||||
libs::spinlock::SpinLock,
|
||||
};
|
||||
|
||||
use super::IrqNumber;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct MsiMsg {
|
||||
pub address_lo: u32,
|
||||
pub address_hi: u32,
|
||||
pub data: u32,
|
||||
}
|
||||
|
||||
impl Debug for MsiMsg {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"MsiMsg {{ address_lo: 0x{:x}, address_hi: 0x{:x}, data: 0x{:x} }}",
|
||||
self.address_lo, self.address_hi, self.data
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl MsiMsg {
|
||||
/// Create a new MSI message
|
||||
pub const fn new(address: u64, data: u32) -> Self {
|
||||
MsiMsg {
|
||||
address_lo: address as u32,
|
||||
address_hi: (address >> 32) as u32,
|
||||
data,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new MSI message
|
||||
pub const fn new_lo_hi(address_lo: u32, address_hi: u32, data: u32) -> Self {
|
||||
MsiMsg {
|
||||
address_lo,
|
||||
address_hi,
|
||||
data,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the address of the MSI message
|
||||
pub const fn address(&self) -> u64 {
|
||||
(self.address_hi as u64) << 32 | self.address_lo as u64
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub struct MsiDesc {
|
||||
inner: SpinLock<InnerMsiDesc>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
struct InnerMsiDesc {
|
||||
/// The base interrupt number
|
||||
irq: IrqNumber,
|
||||
/// The number of vectors used
|
||||
nvec_used: u32,
|
||||
/// Pointer to the device which uses this descriptor
|
||||
dev: Option<Arc<dyn Device>>,
|
||||
/// The last set MSI message cached for reuse
|
||||
msg: MsiMsg,
|
||||
/// Pointer to sysfs device attribute
|
||||
sysfs_attribute: Option<&'static dyn Attribute>,
|
||||
/// Pointer to MSI callback function
|
||||
func: Option<&'static dyn MsiDescFunc>,
|
||||
/// The index of the MSI descriptor
|
||||
index: u32,
|
||||
/// PCI specific msi descriptor data
|
||||
pci_msg: PciIrqMsg,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl MsiDesc {
|
||||
pub const fn new(
|
||||
irq: IrqNumber,
|
||||
nvec_used: u32,
|
||||
dev: Option<Arc<dyn Device>>,
|
||||
index: u32,
|
||||
pci_msg: PciIrqMsg,
|
||||
) -> Self {
|
||||
MsiDesc {
|
||||
inner: SpinLock::new(InnerMsiDesc {
|
||||
irq,
|
||||
nvec_used,
|
||||
dev,
|
||||
msg: MsiMsg {
|
||||
address_lo: 0,
|
||||
address_hi: 0,
|
||||
data: 0,
|
||||
},
|
||||
sysfs_attribute: None,
|
||||
func: None,
|
||||
index,
|
||||
pci_msg,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_msg(&self, msg: MsiMsg) {
|
||||
self.inner.lock().msg = msg;
|
||||
}
|
||||
|
||||
pub fn msg(&self) -> MsiMsg {
|
||||
self.inner.lock().msg
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MsiDescFunc: Debug {
|
||||
/// Callback that may be called when the MSI message
|
||||
/// address or data changes.
|
||||
fn write_msi_msg(&self, data: Arc<dyn MsiDescFuncData>);
|
||||
}
|
||||
|
||||
/// Data parameter for the `MsiDescFunc` callback.
|
||||
pub trait MsiDescFuncData: Send + Sync + Any {}
|
Loading…
x
Reference in New Issue
Block a user