hermit/drivers/net/virtio/
pci.rs1use alloc::vec::Vec;
6use core::str::FromStr;
7
8use pci_types::CommandRegister;
9use smoltcp::phy::ChecksumCapabilities;
10use volatile::VolatileRef;
11
12use crate::arch::pci::PciConfigRegion;
13use crate::drivers::net::virtio::{CtrlQueue, NetDevCfg, RxQueues, TxQueues, VirtioNetDriver};
14use crate::drivers::pci::PciDevice;
15use crate::drivers::virtio::error::{self, VirtioError};
16use crate::drivers::virtio::transport::pci;
17use crate::drivers::virtio::transport::pci::{PciCap, UniCapsColl};
18
19impl VirtioNetDriver {
21 fn map_cfg(cap: &PciCap) -> Option<NetDevCfg> {
22 let dev_cfg = pci::map_dev_cfg::<virtio::net::Config>(cap)?;
23
24 let dev_cfg = VolatileRef::from_ref(dev_cfg);
25
26 Some(NetDevCfg {
27 raw: dev_cfg,
28 dev_id: cap.dev_id(),
29 features: virtio::net::F::empty(),
30 })
31 }
32
33 pub(crate) fn new(
36 caps_coll: UniCapsColl,
37 device: &PciDevice<PciConfigRegion>,
38 ) -> Result<Self, error::VirtioNetError> {
39 let device_id = device.device_id();
40 let UniCapsColl {
41 com_cfg,
42 notif_cfg,
43 isr_cfg,
44 dev_cfg_list,
45 ..
46 } = caps_coll;
47
48 let Some(dev_cfg) = dev_cfg_list.iter().find_map(VirtioNetDriver::map_cfg) else {
49 error!("No dev config. Aborting!");
50 return Err(error::VirtioNetError::NoDevCfg(device_id));
51 };
52
53 let mtu = if let Some(my_mtu) = hermit_var!("HERMIT_MTU") {
54 u16::from_str(&my_mtu).unwrap()
55 } else {
56 1514
58 };
59
60 let send_vqs = TxQueues::new(Vec::new(), &dev_cfg);
61 let recv_vqs = RxQueues::new(Vec::new(), &dev_cfg);
62 Ok(VirtioNetDriver {
63 dev_cfg,
64 com_cfg,
65 isr_stat: isr_cfg,
66 notif_cfg,
67 ctrl_vq: CtrlQueue::new(None),
68 recv_vqs,
69 send_vqs,
70 num_vqs: 0,
71 mtu,
72 irq: device.get_irq().unwrap(),
73 checksums: ChecksumCapabilities::default(),
74 })
75 }
76
77 pub(crate) fn init(
86 device: &PciDevice<PciConfigRegion>,
87 ) -> Result<VirtioNetDriver, VirtioError> {
88 device.set_command(CommandRegister::BUS_MASTER_ENABLE);
90
91 let mut drv = match pci::map_caps(device) {
92 Ok(caps) => match VirtioNetDriver::new(caps, device) {
93 Ok(driver) => driver,
94 Err(vnet_err) => {
95 error!("Initializing new network driver failed. Aborting!");
96 return Err(VirtioError::NetDriver(vnet_err));
97 }
98 },
99 Err(err) => {
100 error!("Mapping capabilities failed. Aborting!");
101 return Err(err);
102 }
103 };
104
105 match drv.init_dev() {
106 Ok(()) => info!(
107 "Network device with id {:x}, has been initialized by driver!",
108 drv.get_dev_id()
109 ),
110 Err(vnet_err) => {
111 drv.set_failed();
112 return Err(VirtioError::NetDriver(vnet_err));
113 }
114 }
115
116 if drv.is_link_up() {
117 info!("Virtio-net link is up after initialization.");
118 } else {
119 info!("Virtio-net link is down after initialization!");
120 }
121
122 Ok(drv)
123 }
124}