1 use core::{any::Any, fmt::Debug}; 2 3 use alloc::sync::Arc; 4 5 use crate::{ 6 driver::{base::device::Device, pci::pci_irq::PciIrqMsg}, 7 filesystem::sysfs::Attribute, 8 libs::spinlock::SpinLock, 9 }; 10 11 use super::IrqNumber; 12 13 #[derive(Clone, Copy)] 14 pub struct MsiMsg { 15 pub address_lo: u32, 16 pub address_hi: u32, 17 pub data: u32, 18 } 19 20 impl Debug for MsiMsg { 21 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 22 write!( 23 f, 24 "MsiMsg {{ address_lo: 0x{:x}, address_hi: 0x{:x}, data: 0x{:x} }}", 25 self.address_lo, self.address_hi, self.data 26 ) 27 } 28 } 29 30 #[allow(dead_code)] 31 impl MsiMsg { 32 /// Create a new MSI message 33 pub const fn new(address: u64, data: u32) -> Self { 34 MsiMsg { 35 address_lo: address as u32, 36 address_hi: (address >> 32) as u32, 37 data, 38 } 39 } 40 41 /// Create a new MSI message 42 pub const fn new_lo_hi(address_lo: u32, address_hi: u32, data: u32) -> Self { 43 MsiMsg { 44 address_lo, 45 address_hi, 46 data, 47 } 48 } 49 50 /// Get the address of the MSI message 51 pub const fn address(&self) -> u64 { 52 (self.address_hi as u64) << 32 | self.address_lo as u64 53 } 54 55 pub const fn new_zeroed() -> Self { 56 MsiMsg { 57 address_lo: 0, 58 address_hi: 0, 59 data: 0, 60 } 61 } 62 } 63 64 #[allow(dead_code)] 65 #[derive(Debug)] 66 pub struct MsiDesc { 67 inner: SpinLock<InnerMsiDesc>, 68 } 69 70 #[allow(dead_code)] 71 #[derive(Debug)] 72 struct InnerMsiDesc { 73 /// The base interrupt number 74 irq: IrqNumber, 75 /// The number of vectors used 76 nvec_used: u32, 77 /// Pointer to the device which uses this descriptor 78 dev: Option<Arc<dyn Device>>, 79 /// The last set MSI message cached for reuse 80 msg: MsiMsg, 81 /// Pointer to sysfs device attribute 82 sysfs_attribute: Option<&'static dyn Attribute>, 83 /// Pointer to MSI callback function 84 func: Option<&'static dyn MsiDescFunc>, 85 /// The index of the MSI descriptor 86 index: u32, 87 /// PCI specific msi descriptor data 88 pci_msg: PciIrqMsg, 89 } 90 91 #[allow(dead_code)] 92 impl MsiDesc { 93 pub const fn new( 94 irq: IrqNumber, 95 nvec_used: u32, 96 dev: Option<Arc<dyn Device>>, 97 index: u32, 98 pci_msg: PciIrqMsg, 99 ) -> Self { 100 MsiDesc { 101 inner: SpinLock::new(InnerMsiDesc { 102 irq, 103 nvec_used, 104 dev, 105 msg: MsiMsg { 106 address_lo: 0, 107 address_hi: 0, 108 data: 0, 109 }, 110 sysfs_attribute: None, 111 func: None, 112 index, 113 pci_msg, 114 }), 115 } 116 } 117 118 pub fn set_msg(&self, msg: MsiMsg) { 119 self.inner.lock().msg = msg; 120 } 121 122 pub fn msg(&self) -> MsiMsg { 123 self.inner.lock().msg 124 } 125 } 126 127 pub trait MsiDescFunc: Debug + Send + Sync { 128 /// Callback that may be called when the MSI message 129 /// address or data changes. 130 fn write_msi_msg(&self, data: Arc<dyn MsiDescFuncData>); 131 } 132 133 /// Data parameter for the `MsiDescFunc` callback. 134 pub trait MsiDescFuncData: Send + Sync + Any {} 135