浏览代码

fix(driver/virtio): 修改pci transport中断初始化的位置 (#1018)

* fix(driver/virtio): 修改pci transport中断初始化的位置
黄铭涛 4 月之前
父节点
当前提交
84c528f53d

+ 7 - 1
kernel/src/driver/block/virtio_blk.rs

@@ -163,8 +163,14 @@ unsafe impl Sync for VirtIOBlkDevice {}
 
 impl VirtIOBlkDevice {
     pub fn new(transport: VirtIOTransport, dev_id: Arc<DeviceId>) -> Option<Arc<Self>> {
+        // 设置中断
+        if let Err(err) = transport.setup_irq(dev_id.clone()) {
+            error!("VirtIOBlkDevice '{dev_id:?}' setup_irq failed: {:?}", err);
+            return None;
+        }
+
         let devname = virtioblk_manager().alloc_id()?;
-        let irq = transport.irq().map(|irq| IrqNumber::new(irq.data()));
+        let irq = Some(transport.irq());
         let device_inner = VirtIOBlk::<HalImpl, VirtIOTransport>::new(transport);
         if let Err(e) = device_inner {
             error!("VirtIOBlkDevice '{dev_id:?}' create failed: {:?}", e);

+ 6 - 0
kernel/src/driver/net/virtio_net.rs

@@ -91,6 +91,12 @@ impl Debug for InnerVirtIONetDevice {
 
 impl VirtIONetDevice {
     pub fn new(transport: VirtIOTransport, dev_id: Arc<DeviceId>) -> Option<Arc<Self>> {
+        // 设置中断
+        if let Err(err) = transport.setup_irq(dev_id.clone()) {
+            error!("VirtIONetDevice '{dev_id:?}' setup_irq failed: {:?}", err);
+            return None;
+        }
+
         let driver_net: VirtIONet<HalImpl, VirtIOTransport, 2> =
             match VirtIONet::<HalImpl, VirtIOTransport, 2>::new(transport, 4096) {
                 Ok(net) => net,

+ 45 - 8
kernel/src/driver/virtio/transport.rs

@@ -1,8 +1,21 @@
-use virtio_drivers::transport::Transport;
+use alloc::{string::ToString, sync::Arc};
 
-use crate::exception::HardwareIrqNumber;
+use virtio_drivers::transport::Transport;
 
-use super::{transport_mmio::VirtIOMmioTransport, transport_pci::PciTransport};
+use crate::{
+    driver::{
+        base::device::DeviceId,
+        pci::{
+            pci::{PciDeviceStructure, PciError},
+            pci_irq::{IrqCommonMsg, IrqSpecificMsg, PciInterrupt, PciIrqError, PciIrqMsg, IRQ},
+        },
+    },
+    exception::IrqNumber,
+};
+
+use super::{
+    irq::DefaultVirtioIrqHandler, transport_mmio::VirtIOMmioTransport, transport_pci::PciTransport,
+};
 
 pub enum VirtIOTransport {
     Pci(PciTransport),
@@ -10,11 +23,35 @@ pub enum VirtIOTransport {
 }
 
 impl VirtIOTransport {
-    pub fn irq(&self) -> Option<HardwareIrqNumber> {
-        match self {
-            VirtIOTransport::Mmio(transport) => Some(transport.irq()),
-            _ => None,
-        }
+    pub fn irq(&self) -> IrqNumber {
+        match self {
+            VirtIOTransport::Pci(transport) => transport.irq(),
+            VirtIOTransport::Mmio(transport) => IrqNumber::new(transport.irq().data()),
+        }
+    }
+
+    /// 设置中断
+    pub fn setup_irq(&self, dev_id: Arc<DeviceId>) -> Result<(), PciError> {
+        if let VirtIOTransport::Pci(transport) = self {
+            let mut pci_device_guard = transport.pci_device();
+            let standard_device = pci_device_guard.as_standard_device_mut().unwrap();
+            standard_device
+                .irq_init(IRQ::PCI_IRQ_MSIX | IRQ::PCI_IRQ_MSI)
+                .ok_or(PciError::PciIrqError(PciIrqError::IrqNotInited))?;
+            // 中断相关信息
+            let msg = PciIrqMsg {
+                irq_common_message: IrqCommonMsg::init_from(
+                    0,
+                    "Virtio_IRQ".to_string(),
+                    &DefaultVirtioIrqHandler,
+                    dev_id,
+                ),
+                irq_specific_message: IrqSpecificMsg::msi_default(),
+            };
+            standard_device.irq_install(msg)?;
+            standard_device.irq_enable(true)?;
+        }
+        return Ok(());
     }
 }
 

+ 12 - 21
kernel/src/driver/virtio/transport_pci.rs

@@ -6,17 +6,16 @@ use crate::driver::pci::pci::{
     PciStandardDeviceBar, PCI_CAP_ID_VNDR,
 };
 
-use crate::driver::pci::pci_irq::{IrqCommonMsg, IrqSpecificMsg, PciInterrupt, PciIrqMsg, IRQ};
 use crate::driver::pci::root::pci_root_0;
 
 use crate::exception::IrqNumber;
 
+use crate::libs::spinlock::{SpinLock, SpinLockGuard};
 use crate::libs::volatile::{
     volread, volwrite, ReadOnly, Volatile, VolatileReadable, VolatileWritable, WriteOnly,
 };
 use crate::mm::VirtAddr;
 
-use alloc::string::ToString;
 use alloc::sync::Arc;
 use core::{
     fmt::{self, Display, Formatter},
@@ -28,7 +27,6 @@ use virtio_drivers::{
     Error, Hal, PhysAddr,
 };
 
-use super::irq::DefaultVirtioIrqHandler;
 use super::VIRTIO_VENDOR_ID;
 
 /// The offset to add to a VirtIO device ID to get the corresponding PCI device ID.
@@ -104,6 +102,7 @@ pub struct PciTransport {
     config_space: Option<NonNull<[u32]>>,
     irq: IrqNumber,
     dev_id: Arc<DeviceId>,
+    device: Arc<SpinLock<PciDeviceStructureGeneralDevice>>,
 }
 
 impl PciTransport {
@@ -140,21 +139,7 @@ impl PciTransport {
         // 目前缺少对PCI设备中断号的统一管理,所以这里需要指定一个中断号。不能与其他中断重复
         let irq_vector = standard_device.irq_vector_mut().unwrap();
         irq_vector.push(irq);
-        standard_device
-            .irq_init(IRQ::PCI_IRQ_MSIX | IRQ::PCI_IRQ_MSI)
-            .ok_or(VirtioPciError::UnableToInitIrq)?;
-        // 中断相关信息
-        let msg = PciIrqMsg {
-            irq_common_message: IrqCommonMsg::init_from(
-                0,
-                "Virtio_IRQ".to_string(),
-                &DefaultVirtioIrqHandler,
-                dev_id.clone(),
-            ),
-            irq_specific_message: IrqSpecificMsg::msi_default(),
-        };
-        standard_device.irq_install(msg)?;
-        standard_device.irq_enable(true)?;
+
         //device_capability为迭代器,遍历其相当于遍历所有的cap空间
         for capability in device.capabilities().unwrap() {
             if capability.id != PCI_CAP_ID_VNDR {
@@ -236,8 +221,17 @@ impl PciTransport {
             config_space,
             irq,
             dev_id,
+            device: Arc::new(SpinLock::new(device.clone())),
         })
     }
+
+    pub fn pci_device(&self) -> SpinLockGuard<PciDeviceStructureGeneralDevice> {
+        self.device.lock()
+    }
+
+    pub fn irq(&self) -> IrqNumber {
+        self.irq
+    }
 }
 
 impl Transport for PciTransport {
@@ -446,8 +440,6 @@ pub enum VirtioPciError {
     /// `VIRTIO_PCI_CAP_NOTIFY_CFG` capability has a `notify_off_multiplier` that is not a multiple
     /// of 2.
     InvalidNotifyOffMultiplier(u32),
-    /// Unable to find capability such as MSIX or MSI.
-    UnableToInitIrq,
     /// No valid `VIRTIO_PCI_CAP_ISR_CFG` capability was found.
     MissingIsrConfig,
     /// An IO BAR was provided rather than a memory BAR.
@@ -477,7 +469,6 @@ impl Display for VirtioPciError {
                 "PCI device vender ID {:#06x} was not the VirtIO vendor ID {:#06x}.",
                 vendor_id, VIRTIO_VENDOR_ID
             ),
-            Self::UnableToInitIrq => write!(f, "Unable to find capability such as MSIX or MSI."),
             Self::MissingCommonConfig => write!(
                 f,
                 "No valid `VIRTIO_PCI_CAP_COMMON_CFG` capability was found."

+ 13 - 1
kernel/src/net/net_core.rs

@@ -7,7 +7,11 @@ use crate::{
     driver::net::{NetDevice, Operstate},
     libs::rwlock::RwLockReadGuard,
     net::{socket::SocketPollMethod, NET_DEVICES},
-    time::timer::{next_n_ms_timer_jiffies, Timer, TimerFunction},
+    time::{
+        sleep::nanosleep,
+        timer::{next_n_ms_timer_jiffies, Timer, TimerFunction},
+        PosixTimeSpec,
+    },
 };
 
 use super::{
@@ -118,6 +122,14 @@ fn dhcp_query() -> Result<(), SystemError> {
                     .remove_default_ipv4_route();
             }
         }
+        // 在睡眠前释放锁
+        drop(binding);
+
+        let sleep_time = PosixTimeSpec {
+            tv_sec: 5,
+            tv_nsec: 0,
+        };
+        let _ = nanosleep(sleep_time)?;
     }
 
     return Err(SystemError::ETIMEDOUT);