Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

virtq: use enum_dispatch #1406

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ talc = { version = "4" }
time = { version = "0.3", default-features = false }
volatile = "0.6"
zerocopy = { version = "0.7", default-features = false }
enum_dispatch = "0.3.13"

[dependencies.smoltcp]
version = "0.11"
Expand Down
24 changes: 13 additions & 11 deletions src/drivers/fs/virtio_fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::drivers::virtio::transport::pci::{ComCfg, IsrStatus, NotifCfg};
use crate::drivers::virtio::virtqueue::error::VirtqError;
use crate::drivers::virtio::virtqueue::split::SplitVq;
use crate::drivers::virtio::virtqueue::{
AvailBufferToken, BufferElem, BufferType, Virtq, VqIndex, VqSize,
AvailBufferToken, BufferElem, BufferType, VirtQueue, Virtq, VqIndex, VqSize,
};
use crate::fs::fuse::{self, FuseInterface, Rsp, RspHeader};
use crate::mm::device_alloc::DeviceAlloc;
Expand All @@ -42,7 +42,7 @@ pub(crate) struct VirtioFsDriver {
pub(super) com_cfg: ComCfg,
pub(super) isr_stat: IsrStatus,
pub(super) notif_cfg: NotifCfg,
pub(super) vqueues: Vec<Box<dyn Virtq>>,
pub(super) vqueues: Vec<VirtQueue>,
pub(super) irq: InterruptLine,
}

Expand Down Expand Up @@ -130,15 +130,17 @@ impl VirtioFsDriver {

// create the queues and tell device about them
for i in 0..vqnum as u16 {
let vq = SplitVq::new(
&mut self.com_cfg,
&self.notif_cfg,
VqSize::from(VIRTIO_MAX_QUEUE_SIZE),
VqIndex::from(i),
self.dev_cfg.features.into(),
)
.unwrap();
self.vqueues.push(Box::new(vq));
let vq = VirtQueue::Split(
SplitVq::new(
&mut self.com_cfg,
&self.notif_cfg,
VqSize::from(VIRTIO_MAX_QUEUE_SIZE),
VqIndex::from(i),
self.dev_cfg.features.into(),
)
.unwrap(),
);
self.vqueues.push(vq);
}

// At this point the device is "live"
Expand Down
7 changes: 3 additions & 4 deletions src/drivers/net/virtio/mmio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
//!
//! The module contains ...

use alloc::boxed::Box;
use alloc::vec::Vec;
use core::str::FromStr;

Expand All @@ -13,7 +12,7 @@ use volatile::VolatileRef;
use crate::drivers::net::virtio::{CtrlQueue, NetDevCfg, RxQueues, TxQueues, VirtioNetDriver};
use crate::drivers::virtio::error::{VirtioError, VirtioNetError};
use crate::drivers::virtio::transport::mmio::{ComCfg, IsrStatus, NotifCfg};
use crate::drivers::virtio::virtqueue::Virtq;
use crate::drivers::virtio::virtqueue::VirtQueue;

// Backend-dependent interface for Virtio network driver
impl VirtioNetDriver {
Expand Down Expand Up @@ -46,8 +45,8 @@ impl VirtioNetDriver {
1514
};

let send_vqs = TxQueues::new(Vec::<Box<dyn Virtq>>::new(), &dev_cfg);
let recv_vqs = RxQueues::new(Vec::<Box<dyn Virtq>>::new(), &dev_cfg);
let send_vqs = TxQueues::new(Vec::<VirtQueue>::new(), &dev_cfg);
let recv_vqs = RxQueues::new(Vec::<VirtQueue>::new(), &dev_cfg);
Ok(VirtioNetDriver {
dev_cfg,
com_cfg: ComCfg::new(registers, 1),
Expand Down
34 changes: 17 additions & 17 deletions src/drivers/net/virtio/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use crate::drivers::virtio::transport::pci::{ComCfg, IsrStatus, NotifCfg};
use crate::drivers::virtio::virtqueue::packed::PackedVq;
use crate::drivers::virtio::virtqueue::split::SplitVq;
use crate::drivers::virtio::virtqueue::{
AvailBufferToken, BufferElem, BufferType, UsedBufferToken, Virtq, VqIndex, VqSize,
AvailBufferToken, BufferElem, BufferType, UsedBufferToken, VirtQueue, Virtq, VqIndex, VqSize,
};
use crate::executor::device::{RxToken, TxToken};
use crate::mm::device_alloc::DeviceAlloc;
Expand All @@ -46,23 +46,23 @@ pub(crate) struct NetDevCfg {
pub features: virtio::net::F,
}

pub struct CtrlQueue(Option<Box<dyn Virtq>>);
pub struct CtrlQueue(Option<VirtQueue>);

impl CtrlQueue {
pub fn new(vq: Option<Box<dyn Virtq>>) -> Self {
pub fn new(vq: Option<VirtQueue>) -> Self {
CtrlQueue(vq)
}
}

pub struct RxQueues {
vqs: Vec<Box<dyn Virtq>>,
vqs: Vec<VirtQueue>,
poll_sender: async_channel::Sender<UsedBufferToken>,
poll_receiver: async_channel::Receiver<UsedBufferToken>,
packet_size: u32,
}

impl RxQueues {
pub fn new(vqs: Vec<Box<dyn Virtq>>, dev_cfg: &NetDevCfg) -> Self {
pub fn new(vqs: Vec<VirtQueue>, dev_cfg: &NetDevCfg) -> Self {
let (poll_sender, poll_receiver) = async_channel::unbounded();

// See Virtio specification v1.1 - 5.1.6.3.1
Expand Down Expand Up @@ -92,11 +92,11 @@ impl RxQueues {
/// Adds a given queue to the underlying vector and populates the queue with RecvBuffers.
///
/// Queues are all populated according to Virtio specification v1.1. - 5.1.6.3.1
fn add(&mut self, mut vq: Box<dyn Virtq>) {
fn add(&mut self, mut vq: VirtQueue) {
const BUFF_PER_PACKET: u16 = 2;
let num_packets: u16 = u16::from(vq.size()) / BUFF_PER_PACKET;
fill_queue(
vq.as_mut(),
&mut vq,
num_packets,
self.packet_size,
self.poll_sender.clone(),
Expand Down Expand Up @@ -185,14 +185,14 @@ fn fill_queue(
/// Structure which handles transmission of packets and delegation
/// to the respective queue structures.
pub struct TxQueues {
vqs: Vec<Box<dyn Virtq>>,
vqs: Vec<VirtQueue>,
/// Indicates, whether the Driver/Device are using multiple
/// queues for communication.
packet_length: u32,
}

impl TxQueues {
pub fn new(vqs: Vec<Box<dyn Virtq>>, dev_cfg: &NetDevCfg) -> Self {
pub fn new(vqs: Vec<VirtQueue>, dev_cfg: &NetDevCfg) -> Self {
let packet_length = if dev_cfg.features.contains(virtio::net::F::GUEST_TSO4)
| dev_cfg.features.contains(virtio::net::F::GUEST_TSO6)
| dev_cfg.features.contains(virtio::net::F::GUEST_UFO)
Expand Down Expand Up @@ -224,7 +224,7 @@ impl TxQueues {
}
}

fn add(&mut self, vq: Box<dyn Virtq>) {
fn add(&mut self, vq: VirtQueue) {
// Currently we are doing nothing with the additional queues. They are inactive and might be used in the
// future
self.vqs.push(vq);
Expand Down Expand Up @@ -370,7 +370,7 @@ impl NetworkDriver for VirtioNetDriver {
}

fill_queue(
self.recv_vqs.vqs[0].as_mut(),
&mut self.recv_vqs.vqs[0],
num_buffers,
self.recv_vqs.packet_size,
self.recv_vqs.poll_sender.clone(),
Expand Down Expand Up @@ -672,7 +672,7 @@ impl VirtioNetDriver {
// Add a control if feature is negotiated
if self.dev_cfg.features.contains(virtio::net::F::CTRL_VQ) {
if self.dev_cfg.features.contains(virtio::net::F::RING_PACKED) {
self.ctrl_vq = CtrlQueue(Some(Box::new(
self.ctrl_vq = CtrlQueue(Some(VirtQueue::Packed(
PackedVq::new(
&mut self.com_cfg,
&self.notif_cfg,
Expand All @@ -683,7 +683,7 @@ impl VirtioNetDriver {
.unwrap(),
)));
} else {
self.ctrl_vq = CtrlQueue(Some(Box::new(
self.ctrl_vq = CtrlQueue(Some(VirtQueue::Split(
SplitVq::new(
&mut self.com_cfg,
&self.notif_cfg,
Expand Down Expand Up @@ -759,7 +759,7 @@ impl VirtioNetDriver {
// Interrupt for receiving packets is wanted
vq.enable_notifs();

self.recv_vqs.add(Box::from(vq));
self.recv_vqs.add(VirtQueue::Packed(vq));

let mut vq = PackedVq::new(
&mut self.com_cfg,
Expand All @@ -772,7 +772,7 @@ impl VirtioNetDriver {
// Interrupt for comunicating that a sended packet left, is not needed
vq.disable_notifs();

self.send_vqs.add(Box::from(vq));
self.send_vqs.add(VirtQueue::Packed(vq));
} else {
let mut vq = SplitVq::new(
&mut self.com_cfg,
Expand All @@ -785,7 +785,7 @@ impl VirtioNetDriver {
// Interrupt for receiving packets is wanted
vq.enable_notifs();

self.recv_vqs.add(Box::from(vq));
self.recv_vqs.add(VirtQueue::Split(vq));

let mut vq = SplitVq::new(
&mut self.com_cfg,
Expand All @@ -798,7 +798,7 @@ impl VirtioNetDriver {
// Interrupt for comunicating that a sended packet left, is not needed
vq.disable_notifs();

self.send_vqs.add(Box::from(vq));
self.send_vqs.add(VirtQueue::Split(vq));
}
}

Expand Down
29 changes: 10 additions & 19 deletions src/drivers/virtio/virtqueue/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,12 @@ use core::mem::MaybeUninit;
use core::{mem, ptr};

use async_channel::TryRecvError;
use enum_dispatch::enum_dispatch;
use packed::PackedVq;
use split::SplitVq;
use virtio::{le32, le64, pvirtq, virtq};

use self::error::VirtqError;
#[cfg(not(feature = "pci"))]
use super::transport::mmio::{ComCfg, NotifCfg};
#[cfg(feature = "pci")]
use super::transport::pci::{ComCfg, NotifCfg};
use crate::arch::mm::{paging, VirtAddr};
use crate::mm::device_alloc::DeviceAlloc;

Expand Down Expand Up @@ -99,6 +98,7 @@ type UsedBufferTokenSender = async_channel::Sender<UsedBufferToken>;
/// might not provide the complete feature set of each queue. Drivers who
/// do need these features should refrain from providing support for both
/// Virtqueue types and use the structs directly instead.
#[enum_dispatch]
pub trait Virtq {
/// The `notif` parameter indicates if the driver wants to have a notification for this specific
/// transfer. This is only for performance optimization. As it is NOT ensured, that the device sees the
Expand Down Expand Up @@ -193,21 +193,6 @@ pub trait Virtq {
notif: bool,
) -> Result<(), VirtqError>;

/// Creates a new Virtq of the specified [VqSize] and the [VqIndex].
/// The index represents the "ID" of the virtqueue.
/// Upon creation the virtqueue is "registered" at the device via the `ComCfg` struct.
///
/// Be aware, that devices define a maximum number of queues and a maximal size they can handle.
fn new(
com_cfg: &mut ComCfg,
notif_cfg: &NotifCfg,
size: VqSize,
index: VqIndex,
features: virtio::F,
) -> Result<Self, VirtqError>
where
Self: Sized;

/// Returns the size of a Virtqueue. This represents the overall size and not the capacity the
/// queue currently has for new descriptors.
fn size(&self) -> VqSize;
Expand Down Expand Up @@ -292,6 +277,12 @@ trait VirtqPrivate {
}
}

#[enum_dispatch(Virtq)]
pub(crate) enum VirtQueue {
Split(SplitVq),
Packed(PackedVq),
}

trait VirtqDescriptor {
fn flags_mut(&mut self) -> &mut virtq::DescF;

Expand Down
46 changes: 24 additions & 22 deletions src/drivers/virtio/virtqueue/packed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,30 @@ impl Virtq for PackedVq {
self.index
}

fn new(
fn size(&self) -> VqSize {
self.size
}

fn has_used_buffers(&self) -> bool {
let desc = &self.descr_ring.ring[usize::from(self.descr_ring.poll_index)];
self.descr_ring.is_marked_used(desc.flags)
}
}

impl VirtqPrivate for PackedVq {
type Descriptor = pvirtq::Desc;

fn create_indirect_ctrl(
buffer_tkn: &AvailBufferToken,
) -> Result<Box<[Self::Descriptor]>, VirtqError> {
Ok(Self::descriptor_iter(buffer_tkn)?
.collect::<Vec<_>>()
.into_boxed_slice())
}
}

impl PackedVq {
pub(crate) fn new(
com_cfg: &mut ComCfg,
notif_cfg: &NotifCfg,
size: VqSize,
Expand Down Expand Up @@ -740,25 +763,4 @@ impl Virtq for PackedVq {
last_next: Default::default(),
})
}

fn size(&self) -> VqSize {
self.size
}

fn has_used_buffers(&self) -> bool {
let desc = &self.descr_ring.ring[usize::from(self.descr_ring.poll_index)];
self.descr_ring.is_marked_used(desc.flags)
}
}

impl VirtqPrivate for PackedVq {
type Descriptor = pvirtq::Desc;

fn create_indirect_ctrl(
buffer_tkn: &AvailBufferToken,
) -> Result<Box<[Self::Descriptor]>, VirtqError> {
Ok(Self::descriptor_iter(buffer_tkn)?
.collect::<Vec<_>>()
.into_boxed_slice())
}
}
Loading
Loading