xref: /DragonOS/kernel/src/driver/virtio/transport_mmio.rs (revision fae6e9ade46a52976ad5d099643d51cc20876448)
1 use core::ptr::NonNull;
2 
3 use alloc::sync::Arc;
4 use fdt::node::FdtNode;
5 use log::info;
6 use system_error::SystemError;
7 use virtio_drivers::transport::{
8     mmio::{MmioTransport, VirtIOHeader},
9     Transport,
10 };
11 
12 use crate::{
13     arch::MMArch,
14     driver::base::device::DeviceId,
15     exception::HardwareIrqNumber,
16     libs::align::page_align_up,
17     mm::{
18         mmio_buddy::{mmio_pool, MMIOSpaceGuard},
19         MemoryManagementArch, PhysAddr,
20     },
21 };
22 
23 pub struct VirtIOMmioTransport {
24     mmio_transport: MmioTransport,
25     _mmio_guard: MMIOSpaceGuard,
26     irq: HardwareIrqNumber,
27     device_id: Arc<DeviceId>,
28 }
29 
30 impl VirtIOMmioTransport {
31     pub fn new(node: FdtNode) -> Result<Self, SystemError> {
32         let reg = node
33             .reg()
34             .ok_or(SystemError::EINVAL)?
35             .next()
36             .ok_or(SystemError::EINVAL)?;
37         let paddr = reg.starting_address as usize;
38         let size = reg.size.unwrap_or(0);
39         let page_offset = paddr % MMArch::PAGE_SIZE;
40         let paddr = paddr - page_offset;
41         let size = page_align_up(size + page_offset);
42         let irq = node
43             .interrupts()
44             .ok_or(SystemError::EINVAL)?
45             .next()
46             .ok_or(SystemError::EINVAL)?;
47 
48         let device_id = DeviceId::new(None, Some(format!("virtio_mmio_{:#X}", paddr))).unwrap();
49 
50         let mmio_guard = mmio_pool().create_mmio(size)?;
51         unsafe { mmio_guard.map_phys(PhysAddr::new(paddr), size) }?;
52 
53         let vaddr = mmio_guard.vaddr() + page_offset;
54         let header = NonNull::new(vaddr.data() as *mut VirtIOHeader).unwrap();
55 
56         match unsafe { MmioTransport::new(header) } {
57             Ok(mmio_transport) => {
58                 info!( "Detected virtio MMIO device with vendor id {:#X}, device type {:?}, version {:?}, hw irq: {}",
59                     mmio_transport.vendor_id(),
60                     mmio_transport.device_type(),
61                     mmio_transport.version(),
62                     irq as u32
63                 );
64 
65                 Ok(Self {
66                     mmio_transport,
67                     _mmio_guard: mmio_guard,
68                     irq: HardwareIrqNumber::new(irq as u32),
69                     device_id,
70                 })
71             }
72             Err(_) => {
73                 // warn!("MmioTransport::new failed: {:?}", e);
74                 Err(SystemError::EINVAL)
75             }
76         }
77     }
78 
79     #[allow(dead_code)]
80     #[inline]
81     pub fn irq(&self) -> HardwareIrqNumber {
82         self.irq
83     }
84 
85     pub fn device_id(&self) -> Arc<DeviceId> {
86         self.device_id.clone()
87     }
88 }
89 
90 impl Transport for VirtIOMmioTransport {
91     fn device_type(&self) -> virtio_drivers::transport::DeviceType {
92         self.mmio_transport.device_type()
93     }
94 
95     fn read_device_features(&mut self) -> u64 {
96         self.mmio_transport.read_device_features()
97     }
98 
99     fn write_driver_features(&mut self, driver_features: u64) {
100         self.mmio_transport.write_driver_features(driver_features)
101     }
102 
103     fn max_queue_size(&mut self, queue: u16) -> u32 {
104         self.mmio_transport.max_queue_size(queue)
105     }
106 
107     fn notify(&mut self, queue: u16) {
108         self.mmio_transport.notify(queue)
109     }
110 
111     fn get_status(&self) -> virtio_drivers::transport::DeviceStatus {
112         self.mmio_transport.get_status()
113     }
114 
115     fn set_status(&mut self, status: virtio_drivers::transport::DeviceStatus) {
116         self.mmio_transport.set_status(status)
117     }
118 
119     fn set_guest_page_size(&mut self, guest_page_size: u32) {
120         self.mmio_transport.set_guest_page_size(guest_page_size)
121     }
122 
123     fn requires_legacy_layout(&self) -> bool {
124         self.mmio_transport.requires_legacy_layout()
125     }
126 
127     fn queue_set(
128         &mut self,
129         queue: u16,
130         size: u32,
131         descriptors: virtio_drivers::PhysAddr,
132         driver_area: virtio_drivers::PhysAddr,
133         device_area: virtio_drivers::PhysAddr,
134     ) {
135         self.mmio_transport
136             .queue_set(queue, size, descriptors, driver_area, device_area)
137     }
138 
139     fn queue_unset(&mut self, queue: u16) {
140         self.mmio_transport.queue_unset(queue)
141     }
142 
143     fn queue_used(&mut self, queue: u16) -> bool {
144         self.mmio_transport.queue_used(queue)
145     }
146 
147     fn ack_interrupt(&mut self) -> bool {
148         self.mmio_transport.ack_interrupt()
149     }
150 
151     fn config_space<T: 'static>(&self) -> virtio_drivers::Result<core::ptr::NonNull<T>> {
152         self.mmio_transport.config_space()
153     }
154 
155     fn finish_init(&mut self) {
156         self.mmio_transport.finish_init()
157     }
158 }
159