Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
14 changes: 13 additions & 1 deletion vm/devices/storage/nvme/src/queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use vmcore::interrupt::Interrupt;

pub struct DoorbellMemory {
mem: GuestMemory,
private_mem: GuestMemory,
offset: u64,
event_idx_offset: Option<u64>,
wakers: Vec<Option<Waker>>,
Expand All @@ -29,14 +30,25 @@ pub struct InvalidDoorbell;

impl DoorbellMemory {
pub fn new(num_qids: u16) -> Self {
let private_mem = GuestMemory::allocate((num_qids as usize) << DOORBELL_STRIDE_BITS);
Self {
mem: GuestMemory::allocate((num_qids as usize) << DOORBELL_STRIDE_BITS),
mem: private_mem.clone(),
private_mem,
offset: 0,
event_idx_offset: None,
wakers: (0..num_qids).map(|_| None).collect(),
}
}

pub fn reset(&mut self) {
self.private_mem
.fill_at(0, 0, self.wakers.len() << DOORBELL_STRIDE_BITS)
.expect("private doorbell memory must be writable");
self.mem = self.private_mem.clone();
self.offset = 0;
self.event_idx_offset = None;
}
Comment thread
jstarks marked this conversation as resolved.

/// Update the memory used to store the doorbell values. This is used to
/// support shadow doorbells, where the values are directly in guest memory.
pub fn replace_mem(
Expand Down
36 changes: 36 additions & 0 deletions vm/devices/storage/nvme/src/tests/shadow_doorbell_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

use crate::PAGE_SIZE64;
use crate::prp::PrpRange;
use crate::queue::DoorbellMemory;
use crate::spec;
use crate::tests::controller_tests::instantiate_and_build_admin_queue;
use crate::tests::controller_tests::wait_for_msi;
Expand All @@ -14,6 +15,7 @@ use pal_async::DefaultDriver;
use pal_async::async_test;
use pci_core::test_helpers::TestPciInterruptController;
use user_driver::backoff::Backoff;
use vmcore::device_state::ChangeDeviceState;
use zerocopy::FromZeros;
use zerocopy::IntoBytes;

Expand Down Expand Up @@ -157,6 +159,40 @@ async fn test_setup_shadow_doorbells(driver: DefaultDriver) {
setup_shadow_doorbells(driver.clone(), &cq_buf, &sq_buf, &gm, &int_controller, None).await;
}

#[async_test]
async fn test_reset_shadow_doorbells(driver: DefaultDriver) {
let cq_buf = PrpRange::new(vec![CQ_BASE], 0, PAGE_SIZE64).unwrap();
let sq_buf = PrpRange::new(vec![SQ_BASE], 0, PAGE_SIZE64).unwrap();
let gm = test_memory();
let int_controller = TestPciInterruptController::new();

let mut nvmec =
setup_shadow_doorbells(driver, &cq_buf, &sq_buf, &gm, &int_controller, None).await;

ChangeDeviceState::reset(&mut nvmec).await;

let shadow_value = 0x1234;
gm.write_plain::<u32>(DOORBELL_BUFFER_BASE, &shadow_value)
.unwrap();
nvmec.write_bar0(0x1000, 0x5678_u32.as_bytes()).unwrap();

assert_eq!(
gm.read_plain::<u32>(DOORBELL_BUFFER_BASE).unwrap(),
shadow_value
);

let mut doorbells = DoorbellMemory::new(2);
assert!(doorbells.try_write(0, shadow_value).is_ok());
doorbells
.replace_mem(gm.clone(), DOORBELL_BUFFER_BASE, None)
.unwrap();
Comment thread
jstarks marked this conversation as resolved.
Outdated
doorbells.reset();
doorbells
.replace_mem(gm.clone(), EVT_IDX_BUFFER_BASE, None)
.unwrap();
assert_eq!(gm.read_plain::<u32>(EVT_IDX_BUFFER_BASE).unwrap(), 0);
}

#[async_test]
async fn test_setup_sq_ring_with_shadow(driver: DefaultDriver) {
let cq_buf = PrpRange::new(vec![CQ_BASE], 0, PAGE_SIZE64).unwrap();
Expand Down
1 change: 1 addition & 0 deletions vm/devices/storage/nvme/src/workers/coordinator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ impl NvmeWorkers {
}
}
}
self.doorbells.write().reset();
}
}

Expand Down
14 changes: 13 additions & 1 deletion vm/devices/storage/nvme_test/src/queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use vmcore::interrupt::Interrupt;

pub struct DoorbellMemory {
mem: GuestMemory,
private_mem: GuestMemory,
offset: u64,
event_idx_offset: Option<u64>,
wakers: Vec<Option<Waker>>,
Expand All @@ -29,14 +30,25 @@ pub struct InvalidDoorbell;

impl DoorbellMemory {
pub fn new(num_qids: u16) -> Self {
let private_mem = GuestMemory::allocate((num_qids as usize) << DOORBELL_STRIDE_BITS);
Self {
mem: GuestMemory::allocate((num_qids as usize) << DOORBELL_STRIDE_BITS),
mem: private_mem.clone(),
private_mem,
offset: 0,
event_idx_offset: None,
wakers: (0..num_qids).map(|_| None).collect(),
}
}

pub fn reset(&mut self) {
self.private_mem
.fill_at(0, 0, self.wakers.len() << DOORBELL_STRIDE_BITS)
.expect("private doorbell memory must be writable");
self.mem = self.private_mem.clone();
self.offset = 0;
self.event_idx_offset = None;
}
Comment thread
jstarks marked this conversation as resolved.

/// Update the memory used to store the doorbell values. This is used to
/// support shadow doorbells, where the values are directly in guest memory.
pub fn replace_mem(
Expand Down
36 changes: 36 additions & 0 deletions vm/devices/storage/nvme_test/src/tests/shadow_doorbell_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

use crate::PAGE_SIZE64;
use crate::prp::PrpRange;
use crate::queue::DoorbellMemory;
use crate::spec;
use crate::tests::controller_tests::instantiate_and_build_admin_queue;
use crate::tests::controller_tests::wait_for_msi;
Expand All @@ -16,6 +17,7 @@ use pal_async::DefaultDriver;
use pal_async::async_test;
use pci_core::test_helpers::TestPciInterruptController;
use user_driver::backoff::Backoff;
use vmcore::device_state::ChangeDeviceState;
use zerocopy::FromZeros;
use zerocopy::IntoBytes;

Expand Down Expand Up @@ -162,6 +164,40 @@ async fn test_setup_shadow_doorbells(driver: DefaultDriver) {
setup_shadow_doorbells(driver.clone(), &cq_buf, &sq_buf, &gm, &int_controller, None).await;
}

#[async_test]
async fn test_reset_shadow_doorbells(driver: DefaultDriver) {
let cq_buf = PrpRange::new(vec![CQ_BASE], 0, PAGE_SIZE64).unwrap();
let sq_buf = PrpRange::new(vec![SQ_BASE], 0, PAGE_SIZE64).unwrap();
let gm = test_memory();
let int_controller = TestPciInterruptController::new();

let mut nvmec =
setup_shadow_doorbells(driver, &cq_buf, &sq_buf, &gm, &int_controller, None).await;

ChangeDeviceState::reset(&mut nvmec).await;

let shadow_value = 0x1234;
gm.write_plain::<u32>(DOORBELL_BUFFER_BASE, &shadow_value)
.unwrap();
nvmec.write_bar0(0x1000, 0x5678_u32.as_bytes()).unwrap();

assert_eq!(
gm.read_plain::<u32>(DOORBELL_BUFFER_BASE).unwrap(),
shadow_value
);

let mut doorbells = DoorbellMemory::new(2);
assert!(doorbells.try_write(0, shadow_value).is_ok());
doorbells
.replace_mem(gm.clone(), DOORBELL_BUFFER_BASE, None)
.unwrap();
Comment thread
jstarks marked this conversation as resolved.
Outdated
doorbells.reset();
doorbells
.replace_mem(gm.clone(), EVT_IDX_BUFFER_BASE, None)
.unwrap();
assert_eq!(gm.read_plain::<u32>(EVT_IDX_BUFFER_BASE).unwrap(), 0);
}

#[async_test]
async fn test_setup_sq_ring_with_shadow(driver: DefaultDriver) {
let cq_buf = PrpRange::new(vec![CQ_BASE], 0, PAGE_SIZE64).unwrap();
Expand Down
1 change: 1 addition & 0 deletions vm/devices/storage/nvme_test/src/workers/coordinator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ impl NvmeWorkers {
}
}
}
self.doorbells.write().reset();
}
}

Expand Down
Loading