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