ladybird/Kernel/Net/E1000NetworkAdapter.h

102 lines
2.8 KiB
C
Raw Normal View History

/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/OwnPtr.h>
#include <Kernel/Bus/PCI/Access.h>
#include <Kernel/Bus/PCI/Device.h>
#include <Kernel/IO.h>
#include <Kernel/Interrupts/IRQHandler.h>
#include <Kernel/Net/NetworkAdapter.h>
#include <Kernel/Random.h>
namespace Kernel {
class E1000NetworkAdapter : public NetworkAdapter
, public PCI::Device
Kernel/PCI: Delete PCI::Device in its current form I created this class a long time ago just to be able to quickly make a PCI device to also represent an interrupt handler (because PCI devices have this capability for most devices). Then after a while I introduced the PCI::DeviceController, which is really almost the same thing (a PCI device class that has Address member in it), but is not tied to interrupts so it can have no interrupts, or spawn interrupt handlers however it wants to seems fit. However I decided it's time to say goodbye for this class for a couple of reasons: 1. It made a whole bunch of weird patterns where you had a PCI::Device and a PCI::DeviceController being used in the topic of implementation, where originally, they meant to be used mutually exclusively (you can't and really don't want to use both). 2. We can really make all the classes that inherit from PCI::Device to inherit from IRQHandler at this point. Later on, when we have MSI interrupts support, we can go further and untie things even more. 3. It makes it possible to simplify the VirtIO implementation to a great extent. While this commit almost doesn't change it, future changes can untangle some complexity in the VirtIO code. For UHCIController, E1000NetworkAdapter, NE2000NetworkAdapter, RTL8139NetworkAdapter, RTL8168NetworkAdapter, E1000ENetworkAdapter we are simply making them to inherit the IRQHandler. This makes some sense, because the first 3 devices will never support anything besides IRQs. For the last 2, they might have MSI support, so when we start to utilize those, we might need to untie these classes from IRQHandler and spawn IRQHandler(s) or MSIHandler(s) as needed. The VirtIODevice class is also a case where we currently need to use both PCI::DeviceController and IRQHandler classes as parents, but it could also be untied from the latter.
2021-08-21 06:55:25 +03:00
, public IRQHandler {
public:
static RefPtr<E1000NetworkAdapter> try_to_initialize(PCI::Address);
virtual bool initialize();
virtual ~E1000NetworkAdapter() override;
virtual void send_raw(ReadonlyBytes) override;
virtual bool link_up() override;
virtual i32 link_speed() override;
virtual bool link_full_duplex() override;
virtual StringView purpose() const override { return class_name(); }
protected:
void setup_interrupts();
void setup_link();
E1000NetworkAdapter(PCI::Address, u8 irq);
virtual bool handle_irq(const RegisterState&) override;
virtual StringView class_name() const override { return "E1000NetworkAdapter"sv; }
struct [[gnu::packed]] e1000_rx_desc {
volatile uint64_t addr { 0 };
volatile uint16_t length { 0 };
volatile uint16_t checksum { 0 };
volatile uint8_t status { 0 };
volatile uint8_t errors { 0 };
volatile uint16_t special { 0 };
};
struct [[gnu::packed]] e1000_tx_desc {
volatile uint64_t addr { 0 };
volatile uint16_t length { 0 };
volatile uint8_t cso { 0 };
volatile uint8_t cmd { 0 };
volatile uint8_t status { 0 };
volatile uint8_t css { 0 };
volatile uint16_t special { 0 };
};
virtual void detect_eeprom();
virtual u32 read_eeprom(u8 address);
void read_mac_address();
void write_command(u16 address, u32);
u32 read_command(u16 address);
void initialize_rx_descriptors();
void initialize_tx_descriptors();
void out8(u16 address, u8);
void out16(u16 address, u16);
void out32(u16 address, u32);
u8 in8(u16 address);
u16 in16(u16 address);
u32 in32(u16 address);
2019-03-10 23:40:09 +01:00
void receive();
static constexpr size_t number_of_rx_descriptors = 32;
static constexpr size_t number_of_tx_descriptors = 8;
IOAddress m_io_base;
VirtualAddress m_mmio_base;
OwnPtr<Memory::Region> m_rx_descriptors_region;
OwnPtr<Memory::Region> m_tx_descriptors_region;
OwnPtr<Memory::Region> m_rx_buffer_region;
OwnPtr<Memory::Region> m_tx_buffer_region;
Array<void*, number_of_rx_descriptors> m_rx_buffers;
Array<void*, number_of_tx_descriptors> m_tx_buffers;
OwnPtr<Memory::Region> m_mmio_region;
u8 m_interrupt_line { 0 };
bool m_has_eeprom { false };
bool m_use_mmio { false };
EntropySource m_entropy_source;
WaitQueue m_wait_queue;
};
}