mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 12:28:12 +00:00

There are now 2 separate classes for almost the same object type: - EnumerableDeviceIdentifier, which is used in the enumeration code for all PCI host controller classes. This is allowed to be moved and copied, as it doesn't support ref-counting. - DeviceIdentifier, which inherits from EnumerableDeviceIdentifier. This class uses ref-counting, and is not allowed to be copied. It has a spinlock member in its structure to allow safely executing complicated IO sequences on a PCI device and its space configuration. There's a static method that allows a quick conversion from EnumerableDeviceIdentifier to DeviceIdentifier while creating a NonnullRefPtr out of it. The reason for doing this is for the sake of integrity and reliablity of the system in 2 places: - Ensure that "complicated" tasks that rely on manipulating PCI device registers are done in a safe manner. For example, determining a PCI BAR space size requires multiple read and writes to the same register, and if another CPU tries to do something else with our selected register, then the result will be a catastrophe. - Allow the PCI API to have a united form around a shared object which actually holds much more data than the PCI::Address structure. This is fundamental if we want to do certain types of optimizations, and be able to support more features of the PCI bus in the foreseeable future. This patch already has several implications: - All PCI::Device(s) hold a reference to a DeviceIdentifier structure being given originally from the PCI::Access singleton. This means that all instances of DeviceIdentifier structures are located in one place, and all references are pointing to that location. This ensures that locking the operation spinlock will take effect in all the appropriate places. - We no longer support adding PCI host controllers and then immediately allow for enumerating it with a lambda function. It was found that this method is extremely broken and too much complicated to work reliably with the new paradigm being introduced in this patch. This means that for Volume Management Devices (Intel VMD devices), we simply first enumerate the PCI bus for such devices in the storage code, and if we find a device, we attach it in the PCI::Access method which will scan for devices behind that bridge and will add new DeviceIdentifier(s) objects to its internal Vector. Afterwards, we just continue as usual with scanning for actual storage controllers, so we will find a corresponding NVMe controllers if there were any behind that VMD bridge.
218 lines
6.7 KiB
C++
218 lines
6.7 KiB
C++
/*
|
|
* Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/NonnullOwnPtrVector.h>
|
|
#include <AK/OwnPtr.h>
|
|
#include <Kernel/Bus/PCI/Access.h>
|
|
#include <Kernel/Bus/PCI/Device.h>
|
|
#include <Kernel/IOWindow.h>
|
|
#include <Kernel/Interrupts/IRQHandler.h>
|
|
#include <Kernel/Net/NetworkAdapter.h>
|
|
#include <Kernel/Random.h>
|
|
|
|
namespace Kernel {
|
|
|
|
// RTL8618 / RTL8111 Driver based on https://people.freebsd.org/~wpaul/RealTek/RTL8111B_8168B_Registers_DataSheet_1.0.pdf
|
|
class RTL8168NetworkAdapter final : public NetworkAdapter
|
|
, public PCI::Device
|
|
, public IRQHandler {
|
|
public:
|
|
static ErrorOr<bool> probe(PCI::DeviceIdentifier const&);
|
|
static ErrorOr<NonnullLockRefPtr<NetworkAdapter>> create(PCI::DeviceIdentifier const&);
|
|
virtual ErrorOr<void> initialize(Badge<NetworkingManagement>) override;
|
|
|
|
virtual ~RTL8168NetworkAdapter() override;
|
|
|
|
virtual void send_raw(ReadonlyBytes) override;
|
|
virtual bool link_up() override { return m_link_up; }
|
|
virtual bool link_full_duplex() override;
|
|
virtual i32 link_speed() override;
|
|
|
|
virtual StringView purpose() const override { return class_name(); }
|
|
virtual StringView device_name() const override { return class_name(); }
|
|
virtual Type adapter_type() const override { return Type::Ethernet; }
|
|
|
|
private:
|
|
// FIXME: should this be increased? (maximum allowed here is 1024) - memory usage vs packet loss chance tradeoff
|
|
static constexpr size_t number_of_rx_descriptors = 64;
|
|
static constexpr size_t number_of_tx_descriptors = 16;
|
|
|
|
RTL8168NetworkAdapter(PCI::DeviceIdentifier const&, u8 irq, NonnullOwnPtr<IOWindow> registers_io_window, NonnullOwnPtr<KString>);
|
|
|
|
virtual bool handle_irq(RegisterState const&) override;
|
|
virtual StringView class_name() const override { return "RTL8168NetworkAdapter"sv; }
|
|
|
|
bool determine_supported_version() const;
|
|
|
|
struct [[gnu::packed]] TXDescriptor {
|
|
volatile u16 frame_length; // top 2 bits are reserved
|
|
volatile u16 flags;
|
|
volatile u16 vlan_tag;
|
|
volatile u16 vlan_flags;
|
|
volatile u32 buffer_address_low;
|
|
volatile u32 buffer_address_high;
|
|
|
|
// flags bit field
|
|
static constexpr u16 Ownership = 0x8000u;
|
|
static constexpr u16 EndOfRing = 0x4000u;
|
|
static constexpr u16 FirstSegment = 0x2000u;
|
|
static constexpr u16 LastSegment = 0x1000u;
|
|
static constexpr u16 LargeSend = 0x800u;
|
|
};
|
|
|
|
static_assert(AssertSize<TXDescriptor, 16u>());
|
|
|
|
struct [[gnu::packed]] RXDescriptor {
|
|
volatile u16 buffer_size; // top 2 bits are reserved
|
|
volatile u16 flags;
|
|
volatile u16 vlan_tag;
|
|
volatile u16 vlan_flags;
|
|
volatile u32 buffer_address_low;
|
|
volatile u32 buffer_address_high;
|
|
|
|
// flags bit field
|
|
static constexpr u16 Ownership = 0x8000u;
|
|
static constexpr u16 EndOfRing = 0x4000u;
|
|
static constexpr u16 FirstSegment = 0x2000u;
|
|
static constexpr u16 LastSegment = 0x1000u;
|
|
static constexpr u16 MulticastPacket = 0x800u;
|
|
static constexpr u16 PhysicalPacket = 0x400u;
|
|
static constexpr u16 BroadcastPacket = 0x200u;
|
|
static constexpr u16 WatchdogTimerExpired = 0x40;
|
|
static constexpr u16 ErrorSummary = 0x20;
|
|
static constexpr u16 RuntPacket = 0x10;
|
|
static constexpr u16 CRCError = 0x8;
|
|
};
|
|
|
|
static_assert(AssertSize<RXDescriptor, 16u>());
|
|
|
|
enum class ChipVersion : u8 {
|
|
Unknown = 0,
|
|
Version1 = 1,
|
|
Version2 = 2,
|
|
Version3 = 3,
|
|
Version4 = 4,
|
|
Version5 = 5,
|
|
Version6 = 6,
|
|
Version7 = 7,
|
|
Version8 = 8,
|
|
Version9 = 9,
|
|
Version10 = 10,
|
|
Version11 = 11,
|
|
Version12 = 12,
|
|
Version13 = 13,
|
|
Version14 = 14,
|
|
Version15 = 15,
|
|
Version16 = 16,
|
|
Version17 = 17,
|
|
Version18 = 18,
|
|
Version19 = 19,
|
|
Version20 = 20,
|
|
Version21 = 21,
|
|
Version22 = 22,
|
|
Version23 = 23,
|
|
Version24 = 24,
|
|
Version25 = 25,
|
|
Version26 = 26,
|
|
Version27 = 27,
|
|
Version28 = 28,
|
|
Version29 = 29,
|
|
Version30 = 30
|
|
};
|
|
|
|
void identify_chip_version();
|
|
StringView possible_device_name();
|
|
|
|
void reset();
|
|
void read_mac_address();
|
|
void set_phy_speed();
|
|
void start_hardware();
|
|
void initialize();
|
|
void startup();
|
|
|
|
void configure_phy();
|
|
void configure_phy_b_1();
|
|
void configure_phy_b_2();
|
|
void configure_phy_e_2();
|
|
void configure_phy_h_1();
|
|
void configure_phy_h_2();
|
|
|
|
void rar_exgmac_set();
|
|
|
|
void hardware_quirks();
|
|
void hardware_quirks_b_1();
|
|
void hardware_quirks_b_2();
|
|
void hardware_quirks_e_2();
|
|
void hardware_quirks_h();
|
|
|
|
void initialize_rx_descriptors();
|
|
void initialize_tx_descriptors();
|
|
|
|
void receive();
|
|
|
|
void out8(u16 address, u8 data);
|
|
void out16(u16 address, u16 data);
|
|
void out32(u16 address, u32 data);
|
|
void out64(u16 address, u64 data);
|
|
u8 in8(u16 address);
|
|
u16 in16(u16 address);
|
|
u32 in32(u16 address);
|
|
|
|
void phy_out(u8 address, u16 data);
|
|
u16 phy_in(u8 address);
|
|
void phy_update(u32 address, u32 set, u32 clear);
|
|
struct PhyRegister {
|
|
u16 address;
|
|
u16 data;
|
|
};
|
|
void phy_out_batch(const PhyRegister[], size_t length);
|
|
|
|
void extended_phy_out(u8 address, u16 data);
|
|
u16 extended_phy_in(u8 address);
|
|
struct EPhyUpdate {
|
|
u32 offset;
|
|
u16 clear;
|
|
u16 set;
|
|
};
|
|
void extended_phy_initialize(const EPhyUpdate[], size_t length);
|
|
|
|
void eri_out(u32 address, u32 mask, u32 data, u32 type);
|
|
u32 eri_in(u32 address, u32 type);
|
|
void eri_update(u32 address, u32 mask, u32 set, u32 clear, u32 type);
|
|
struct ExgMacRegister {
|
|
u16 address;
|
|
u16 mask;
|
|
u32 value;
|
|
};
|
|
void exgmac_out_batch(const ExgMacRegister[], size_t length);
|
|
|
|
void csi_out(u32 address, u32 data);
|
|
u32 csi_in(u32 address);
|
|
void csi_enable(u32 bits);
|
|
|
|
void ocp_out(u32 address, u32 data);
|
|
u32 ocp_in(u32 address);
|
|
|
|
void ocp_phy_out(u32 address, u32 data);
|
|
u16 ocp_phy_in(u32 address);
|
|
|
|
ChipVersion m_version { ChipVersion::Unknown };
|
|
bool m_version_uncertain { true };
|
|
NonnullOwnPtr<IOWindow> m_registers_io_window;
|
|
u32 m_ocp_base_address { 0 };
|
|
OwnPtr<Memory::Region> m_rx_descriptors_region;
|
|
NonnullOwnPtrVector<Memory::Region> m_rx_buffers_regions;
|
|
u16 m_rx_free_index { 0 };
|
|
OwnPtr<Memory::Region> m_tx_descriptors_region;
|
|
NonnullOwnPtrVector<Memory::Region> m_tx_buffers_regions;
|
|
u16 m_tx_free_index { 0 };
|
|
bool m_link_up { false };
|
|
EntropySource m_entropy_source;
|
|
WaitQueue m_wait_queue;
|
|
};
|
|
}
|