ladybird/Kernel/Bus/VirtIO/Device.h
Liav A 7718842829 Kernel/VirtIO: Ensure proper error propagation in core methods
Simplify core methods in the VirtIO bus handling code by ensuring proper
error propagation. This makes initialization of queues, handling changes
in device configuration, and other core patterns more readable as well.

It also allows us to remove the obnoxious pattern of checking for
boolean "success" and if we get false answer then returning an actual
errno code.
2023-09-24 19:54:23 -06:00

100 lines
2.7 KiB
C++

/*
* Copyright (c) 2021, the SerenityOS developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <Kernel/Bus/PCI/Access.h>
#include <Kernel/Bus/PCI/Device.h>
#include <Kernel/Bus/VirtIO/Definitions.h>
#include <Kernel/Bus/VirtIO/Queue.h>
#include <Kernel/Bus/VirtIO/Transport/Entity.h>
#include <Kernel/Bus/VirtIO/Transport/InterruptHandler.h>
#include <Kernel/Interrupts/IRQHandler.h>
#include <Kernel/Library/IOWindow.h>
#include <Kernel/Memory/MemoryManager.h>
namespace Kernel::VirtIO {
void detect();
class Device {
public:
virtual ~Device() = default;
virtual ErrorOr<void> initialize_virtio_resources();
bool handle_irq(Badge<TransportInterruptHandler>);
protected:
virtual StringView class_name() const { return "VirtIO::Device"sv; }
explicit Device(NonnullOwnPtr<TransportEntity>);
void mask_status_bits(u8 status_mask);
void set_status_bit(u8);
ErrorOr<void> setup_queues(u16 requested_queue_count = 0);
void finish_init();
Queue& get_queue(u16 queue_index)
{
VERIFY(queue_index < m_queue_count);
return *m_queues[queue_index];
}
Queue const& get_queue(u16 queue_index) const
{
VERIFY(queue_index < m_queue_count);
return *m_queues[queue_index];
}
template<typename F>
ErrorOr<void> negotiate_features(F f)
{
u64 device_features = m_transport_entity->get_device_features();
u64 accept_features = f(device_features);
VERIFY(!(~device_features & accept_features));
return accept_device_features(device_features, accept_features);
}
static bool is_feature_set(u64 feature_set, u64 test_feature)
{
// features can have more than one bit
return (feature_set & test_feature) == test_feature;
}
bool is_feature_accepted(u64 feature) const
{
VERIFY(m_did_accept_features);
return is_feature_set(m_accepted_features, feature);
}
void supply_chain_and_notify(u16 queue_index, QueueChain& chain);
virtual ErrorOr<void> handle_device_config_change() = 0;
virtual void handle_queue_update(u16 queue_index) = 0;
TransportEntity& transport_entity() { return *m_transport_entity; }
private:
ErrorOr<void> accept_device_features(u64 device_features, u64 accepted_features);
ErrorOr<void> setup_queue(u16 queue_index);
ErrorOr<void> activate_queue(u16 queue_index);
void notify_queue(u16 queue_index);
Vector<NonnullOwnPtr<Queue>> m_queues;
StringView const m_class_name;
u16 m_queue_count { 0 };
u8 m_status { 0 };
u64 m_accepted_features { 0 };
bool m_did_accept_features { false };
bool m_did_setup_queues { false };
NonnullOwnPtr<TransportEntity> const m_transport_entity;
};
}