WIP: Make I/O completion queue creation async.

This commit is contained in:
4lDO2
2020-04-30 14:48:43 +02:00
parent cbeb0070ec
commit 3207f5a009
+56 -35
View File
@@ -1,3 +1,4 @@
use std::convert::TryFrom;
use std::collections::BTreeMap;
use std::fs::File;
use std::sync::{Mutex, RwLock};
@@ -93,7 +94,7 @@ pub struct MsixCfg {
pub pba: &'static mut [Mmio<u64>],
}
#[derive(Clone, Copy)]
#[derive(Clone, Copy, Debug, Default)]
#[repr(packed)]
pub struct NvmeCmd {
/// Opcode
@@ -124,11 +125,12 @@ pub struct NvmeCmd {
cdw15: u32,
}
pub struct IoCompletionQueueCreateInfo {
}
impl NvmeCmd {
pub fn create_io_completion_queue(cid: u16, qid: u16, ptr: usize, size: u16) -> Self {
pub fn create_io_completion_queue(cid: u16, qid: u16, ptr: usize, size: u16, iv: Option<u16>) -> Self {
const DW11_PHYSICALLY_CONTIGUOUS_BIT: u32 = 0x0000_0001;
const DW11_ENABLE_INTERRUPTS_BIT: u32 = 0x0000_0002;
const DW11_INTERRUPT_VECTOR_SHIFT: u8 = 16;
Self {
opcode: 5,
flags: 0,
@@ -138,7 +140,13 @@ impl NvmeCmd {
mptr: 0,
dptr: [ptr as u64, 0],
cdw10: ((size as u32) << 16) | (qid as u32),
cdw11: 1 /* Physically Contiguous */, //TODO: IV, IEN
cdw11: DW11_PHYSICALLY_CONTIGUOUS_BIT | if let Some(iv) = iv {
// enable interrupts if a vector is present
DW11_ENABLE_INTERRUPTS_BIT
| (u32::from(iv) << DW11_INTERRUPT_VECTOR_SHIFT)
} else { 0 },
cdw12: 0,
cdw13: 0,
cdw14: 0,
@@ -217,13 +225,21 @@ impl NvmeCmd {
cdw15: 0,
}
}
pub fn get_features(cid: u16, ptr: usize, fid: u8) -> Self {
Self {
opcode: 0xA,
dptr: [ptr as u64, 0],
cdw10: u32::from(fid), // TODO: SEL
.. Default::default()
}
}
pub fn io_read(cid: u16, nsid: u32, lba: u64, blocks_1: u16, ptr0: u64, ptr1: u64) -> Self {
Self {
opcode: 2,
flags: 1 << 6,
cid: cid,
nsid: nsid,
cid,
nsid,
_rsvd: 0,
mptr: 0,
dptr: [ptr0, ptr1],
@@ -240,8 +256,8 @@ impl NvmeCmd {
Self {
opcode: 1,
flags: 1 << 6,
cid: cid,
nsid: nsid,
cid,
nsid,
_rsvd: 0,
mptr: 0,
dptr: [ptr0, ptr1],
@@ -617,7 +633,32 @@ impl Nvme {
block_size: 512, // TODO
}
}
pub async fn create_io_completion_queue(&self, io_cq_id: CqId, vector: Option<u16>) {
let (ptr, len) = {
let mut completion_queues_guard = self.completion_queues.write().unwrap();
let queue_guard = completion_queues_guard.entry(io_cq_id).or_insert_with(|| {
let queue = NvmeCompQueue::new().expect("nvmed: failed to allocate I/O completion queue");
let sqs = SmallVec::new();
Mutex::new((queue, sqs))
}).get_mut().unwrap();
let &(ref queue, _) = &*queue_guard;
(queue.data.physical(), queue.data.len())
};
let len = u16::try_from(len).expect("nvmed: internal error: I/O CQ longer than 2^16 entries");
let raw_len = len.checked_sub(1).expect("nvmed: internal error: CQID 0 for I/O CQ");
let cmd_id = self.submit_admin_command(|cid| NvmeCmd::create_io_completion_queue(
cid, io_cq_id, ptr, raw_len, vector,
));
let comp = self.admin_queue_completion(cmd_id).await;
if let Some(vector) = vector {
self.cqs_for_ivs.write().unwrap().entry(vector).or_insert_with(SmallVec::new).push(io_cq_id);
}
}
pub async fn init_with_queues(&self) -> BTreeMap<u32, NvmeNamespace> {
let ((), nsids) = futures::join!(self.identify_controller(), self.identify_namespace_list(0));
@@ -627,32 +668,11 @@ impl Nvme {
namespaces.insert(nsid, self.identify_namespace(nsid).await);
}
for io_qid in 1..self.completion_queues.len() {
let (ptr, len) = {
let queue = &self.completion_queues[io_qid];
(queue.data.physical(), queue.data.len())
};
// println!(" - Attempting to create I/O completion queue {}", io_qid);
{
let qid = 0;
let queue = &mut self.submission_queues[qid];
let cid = queue.i as u16;
let entry = NvmeCmd::create_io_completion_queue(
cid, io_qid as u16, ptr, (len - 1) as u16
);
let tail = queue.submit(entry);
self.submission_queue_tail(qid as u16, tail as u16);
}
// println!(" - Waiting to create I/O completion queue {}", io_qid);
{
let qid = 0;
let queue = &mut self.completion_queues[qid];
let (head, entry) = queue.complete_spin();
self.completion_queue_head(qid as u16, head as u16);
}
// TODO: Multiple queues
for io_qid in 1u16..=1 {
self.create_io_completion_queue(io_qid, Some(0)).await;
}
/*
for io_qid in 1..self.submission_queues.len() {
let (ptr, len) = {
@@ -681,6 +701,7 @@ impl Nvme {
self.completion_queue_head(qid as u16, head as u16);
}
}
*/
// println!(" - Complete");