/* * Copyright (c) 2021, Pankaj R * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include namespace Kernel { struct DoorbellRegister { u32 sq_tail; u32 cq_head; }; class AsyncBlockDeviceRequest; class NVMeQueue : public RefCounted { public: static ErrorOr> try_create(u16 qid, Optional irq, u32 q_depth, OwnPtr cq_dma_region, NonnullRefPtrVector cq_dma_page, OwnPtr sq_dma_region, NonnullRefPtrVector sq_dma_page, Memory::TypedMapping db_regs); bool is_admin_queue() { return m_admin_queue; }; u16 submit_sync_sqe(NVMeSubmission&); void read(AsyncBlockDeviceRequest& request, u16 nsid, u64 index, u32 count); void write(AsyncBlockDeviceRequest& request, u16 nsid, u64 index, u32 count); virtual void submit_sqe(NVMeSubmission&); virtual ~NVMeQueue(); protected: u32 process_cq(); void update_sq_doorbell() { m_db_regs->sq_tail = m_sq_tail; } NVMeQueue(NonnullOwnPtr rw_dma_region, Memory::PhysicalPage const& rw_dma_page, u16 qid, u32 q_depth, OwnPtr cq_dma_region, NonnullRefPtrVector cq_dma_page, OwnPtr sq_dma_region, NonnullRefPtrVector sq_dma_page, Memory::TypedMapping db_regs); private: bool cqe_available(); void update_cqe_head(); virtual void complete_current_request(u16 status) = 0; void update_cq_doorbell() { m_db_regs->cq_head = m_cq_head; } protected: Spinlock m_cq_lock { LockRank::Interrupts }; RefPtr m_current_request; NonnullOwnPtr m_rw_dma_region; Spinlock m_request_lock; private: u16 m_qid {}; u8 m_cq_valid_phase { 1 }; u16 m_sq_tail {}; u16 m_prev_sq_tail {}; u16 m_cq_head {}; bool m_admin_queue { false }; u32 m_qdepth {}; Spinlock m_sq_lock { LockRank::Interrupts }; OwnPtr m_cq_dma_region; NonnullRefPtrVector m_cq_dma_page; Span m_sqe_array; OwnPtr m_sq_dma_region; NonnullRefPtrVector m_sq_dma_page; Span m_cqe_array; Memory::TypedMapping m_db_regs; NonnullRefPtr m_rw_dma_page; }; }