Kernel: Write simple working E1000 and E1000E drivers
This commit is contained in:
@@ -1,62 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/UniqPtr.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/Networking/NetworkDriver.h>
|
||||
#include <kernel/PCI.h>
|
||||
|
||||
#define E1000_NUM_RX_DESC 32
|
||||
#define E1000_NUM_TX_DESC 8
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class E1000 final : public NetworkDriver, public Interruptable
|
||||
{
|
||||
public:
|
||||
static bool probe(PCI::Device&);
|
||||
static BAN::ErrorOr<BAN::UniqPtr<E1000>> create(PCI::Device&);
|
||||
~E1000();
|
||||
|
||||
virtual uint8_t* get_mac_address() override { return m_mac_address; }
|
||||
virtual BAN::ErrorOr<void> send_packet(const void* data, uint16_t len) override;
|
||||
|
||||
virtual bool link_up() override { return m_link_up; }
|
||||
virtual int link_speed() override;
|
||||
|
||||
virtual void handle_irq() override { ASSERT_NOT_REACHED(); }
|
||||
|
||||
private:
|
||||
E1000(PCI::Device& pci_device) : m_pci_device(pci_device) {}
|
||||
BAN::ErrorOr<void> initialize();
|
||||
|
||||
static void interrupt_handler();
|
||||
|
||||
uint32_t read32(uint16_t reg);
|
||||
void write32(uint16_t reg, uint32_t value);
|
||||
|
||||
void detect_eeprom();
|
||||
uint32_t eeprom_read(uint8_t addr);
|
||||
BAN::ErrorOr<void> read_mac_address();
|
||||
|
||||
void initialize_rx();
|
||||
void initialize_tx();
|
||||
|
||||
void enable_link();
|
||||
BAN::ErrorOr<void> enable_interrupts();
|
||||
|
||||
void handle_receive();
|
||||
|
||||
private:
|
||||
PCI::Device& m_pci_device;
|
||||
BAN::UniqPtr<PCI::BarRegion> m_bar_region;
|
||||
bool m_has_eerprom { false };
|
||||
uint8_t m_mac_address[6] {};
|
||||
uint16_t m_rx_current {};
|
||||
uint16_t m_tx_current {};
|
||||
struct e1000_rx_desc* m_rx_descs[E1000_NUM_RX_DESC] {};
|
||||
struct e1000_tx_desc* m_tx_descs[E1000_NUM_TX_DESC] {};
|
||||
bool m_link_up { false };
|
||||
};
|
||||
|
||||
}
|
||||
202
kernel/include/kernel/Networking/E1000/Definitions.h
Normal file
202
kernel/include/kernel/Networking/E1000/Definitions.h
Normal file
@@ -0,0 +1,202 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
enum E1000_REG : uint32_t
|
||||
{
|
||||
REG_CTRL = 0x0000,
|
||||
REG_STATUS = 0x0008,
|
||||
REG_EERD = 0x0014,
|
||||
REG_ICR = 0x00C0,
|
||||
REG_ITR = 0x00C4,
|
||||
REG_IMS = 0x00D0,
|
||||
REG_IMC = 0x00D8,
|
||||
REG_IVAR = 0x00E4,
|
||||
REG_EITR = 0x00E8,
|
||||
REG_RCTL = 0x0100,
|
||||
REG_TCTL = 0x0400,
|
||||
REG_TIPG = 0x0410,
|
||||
REG_RDBAL0 = 0x2800,
|
||||
REG_RDBAH0 = 0x2804,
|
||||
REG_RDLEN0 = 0x2808,
|
||||
REG_RDH0 = 0x2810,
|
||||
REG_RDT0 = 0x2818,
|
||||
REG_TDBAL = 0x3800,
|
||||
REG_TDBAH = 0x3804,
|
||||
REG_TDLEN = 0x3808,
|
||||
REG_TDH = 0x3810,
|
||||
REG_TDT = 0x3818,
|
||||
REG_MTA = 0x5200,
|
||||
};
|
||||
|
||||
enum E1000_CTRL : uint32_t
|
||||
{
|
||||
CTRL_FD = 1u << 0,
|
||||
CTRL_GIOMD = 1u << 2,
|
||||
CTRL_ASDE = 1u << 5,
|
||||
CTRL_SLU = 1u << 6,
|
||||
CTRL_FRCSPD = 1u << 11,
|
||||
CTRL_FCRDBLX = 1u << 12,
|
||||
CTRL_ADVD3WUC = 1u << 20,
|
||||
CTRL_RST = 1u << 26,
|
||||
CTRL_RFCE = 1u << 27,
|
||||
CTRL_TFCE = 1u << 28,
|
||||
CTRL_VME = 1u << 30,
|
||||
CTRL_PHY_RST = 1u << 31,
|
||||
|
||||
CTRL_SPEED_10MB = 0b00 << 8,
|
||||
CTRL_SPEED_100MB = 0b01 << 8,
|
||||
CTRL_SPEED_1000MB1 = 0b10 << 8,
|
||||
CTRL_SPEED_1000MB2 = 0b11 << 8,
|
||||
};
|
||||
|
||||
enum E1000_STATUS : uint32_t
|
||||
{
|
||||
STATUS_LU = 1 << 1,
|
||||
|
||||
STATUS_SPEED_MASK = 0b11 << 6,
|
||||
STATUS_SPEED_10MB = 0b00 << 6,
|
||||
STATUS_SPEED_100MB = 0b01 << 6,
|
||||
STATUS_SPEED_1000MB1 = 0b10 << 6,
|
||||
STATUS_SPEED_1000MB2 = 0b11 << 6,
|
||||
};
|
||||
|
||||
enum E1000_ICR : uint32_t
|
||||
{
|
||||
ICR_TXDW = 1 << 0,
|
||||
ICR_TXQE = 1 << 1,
|
||||
ICR_LSC = 1 << 2,
|
||||
ICR_RXDMT0 = 1 << 4,
|
||||
ICR_RXO = 1 << 6,
|
||||
ICR_RXT0 = 1 << 7,
|
||||
ICR_MDAC = 1 << 9,
|
||||
ICR_TXD_LOW = 1 << 15,
|
||||
ICR_SRPD = 1 << 16,
|
||||
ICR_ACK = 1 << 17,
|
||||
ICR_MNG = 1 << 18,
|
||||
ICR_RxQ0 = 1 << 20,
|
||||
ICR_RxQ1 = 1 << 21,
|
||||
ICR_TxQ0 = 1 << 22,
|
||||
ICR_TxQ1 = 1 << 23,
|
||||
ICR_Other = 1 << 24,
|
||||
};
|
||||
|
||||
enum E1000_IMS : uint32_t
|
||||
{
|
||||
IMS_TXDW = 1 << 0,
|
||||
IMS_TXQE = 1 << 1,
|
||||
IMS_LSC = 1 << 2,
|
||||
IMS_RXDMT0 = 1 << 4,
|
||||
IMS_RXO = 1 << 6,
|
||||
IMS_RXT0 = 1 << 7,
|
||||
IMS_MDAC = 1 << 9,
|
||||
IMS_TXD_LOW = 1 << 15,
|
||||
IMS_SRPD = 1 << 16,
|
||||
IMS_ACK = 1 << 17,
|
||||
IMS_MNG = 1 << 18,
|
||||
IMS_RxQ0 = 1 << 20,
|
||||
IMS_RxQ1 = 1 << 21,
|
||||
IMS_TxQ0 = 1 << 22,
|
||||
IMS_TxQ1 = 1 << 23,
|
||||
IMS_Other = 1 << 24,
|
||||
};
|
||||
|
||||
enum E1000_IMC : uint32_t
|
||||
{
|
||||
IMC_TXDW = 1 << 0,
|
||||
IMC_TXQE = 1 << 1,
|
||||
IMC_LSC = 1 << 2,
|
||||
IMC_RXDMT0 = 1 << 4,
|
||||
IMC_RXO = 1 << 6,
|
||||
IMC_RXT0 = 1 << 7,
|
||||
IMC_MDAC = 1 << 9,
|
||||
IMC_TXD_LOW = 1 << 15,
|
||||
IMC_SRPD = 1 << 16,
|
||||
IMC_ACK = 1 << 17,
|
||||
IMC_MNG = 1 << 18,
|
||||
IMC_RxQ0 = 1 << 20,
|
||||
IMC_RxQ1 = 1 << 21,
|
||||
IMC_TxQ0 = 1 << 22,
|
||||
IMC_TxQ1 = 1 << 23,
|
||||
IMC_Other = 1 << 24,
|
||||
};
|
||||
|
||||
enum E1000_TCTL : uint32_t
|
||||
{
|
||||
TCTL_EN = 1 << 1,
|
||||
TCTL_PSP = 1 << 3,
|
||||
TCTL_CT_IEEE = 15 << 4,
|
||||
TCTL_SWXOFF = 1 << 22,
|
||||
TCTL_PBE = 1 << 23,
|
||||
TCTL_RCTL = 1 << 24,
|
||||
TCTL_UNORTX = 1 << 25,
|
||||
TCTL_MULR = 1 << 28,
|
||||
};
|
||||
|
||||
enum E1000_RCTL : uint32_t
|
||||
{
|
||||
RCTL_EN = 1 << 1,
|
||||
RCTL_SBP = 1 << 2,
|
||||
RCTL_UPE = 1 << 3,
|
||||
RCTL_MPE = 1 << 4,
|
||||
RCTL_BAM = 1 << 15,
|
||||
RCTL_VFE = 1 << 18,
|
||||
RCTL_CFIEN = 1 << 19,
|
||||
RCTL_CFI = 1 << 20,
|
||||
RCTL_DPF = 1 << 22,
|
||||
RCTL_PMCF = 1 << 23,
|
||||
RCTL_BSEX = 1 << 25,
|
||||
RCTL_SECRC = 1 << 26,
|
||||
|
||||
RCTL_RDMTS_1_2 = 0b00 << 8,
|
||||
RCTL_RDMTS_1_4 = 0b01 << 8,
|
||||
RCTL_RDMTS_1_8 = 0b10 << 8,
|
||||
|
||||
RCTL_LBM_NORMAL = 0b00 << 6,
|
||||
RCTL_LBM_MAC = 0b01 << 6,
|
||||
|
||||
RCTL_BSIZE_256 = (0b11 << 16),
|
||||
RCTL_BSIZE_512 = (0b10 << 16),
|
||||
RCTL_BSIZE_1024 = (0b01 << 16),
|
||||
RCTL_BSIZE_2048 = (0b00 << 16),
|
||||
RCTL_BSIZE_4096 = (0b11 << 16) | RCTL_BSEX,
|
||||
RCTL_BSIZE_8192 = (0b10 << 16) | RCTL_BSEX,
|
||||
RCTL_BSIZE_16384 = (0b01 << 16) | RCTL_BSEX,
|
||||
};
|
||||
|
||||
enum E1000_CMD : uint8_t
|
||||
{
|
||||
CMD_EOP = 1 << 0,
|
||||
CMD_IFCS = 1 << 1,
|
||||
CMD_IC = 1 << 2,
|
||||
CMD_RS = 1 << 3,
|
||||
CMD_DEXT = 1 << 5,
|
||||
CMD_VLE = 1 << 6,
|
||||
CMD_IDE = 1 << 7,
|
||||
};
|
||||
|
||||
struct e1000_rx_desc
|
||||
{
|
||||
uint64_t addr;
|
||||
uint16_t length;
|
||||
uint16_t checksum;
|
||||
uint8_t status;
|
||||
uint8_t errors;
|
||||
uint16_t special;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct e1000_tx_desc
|
||||
{
|
||||
uint64_t addr;
|
||||
uint16_t length;
|
||||
uint8_t cso;
|
||||
uint8_t cmd;
|
||||
uint8_t status;
|
||||
uint8_t css;
|
||||
uint16_t special;
|
||||
} __attribute__((packed));
|
||||
|
||||
}
|
||||
79
kernel/include/kernel/Networking/E1000/E1000.h
Normal file
79
kernel/include/kernel/Networking/E1000/E1000.h
Normal file
@@ -0,0 +1,79 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/UniqPtr.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/Memory/DMARegion.h>
|
||||
#include <kernel/Networking/E1000/Definitions.h>
|
||||
#include <kernel/Networking/NetworkInterface.h>
|
||||
#include <kernel/PCI.h>
|
||||
|
||||
#define E1000_RX_DESCRIPTOR_COUNT 256
|
||||
#define E1000_TX_DESCRIPTOR_COUNT 256
|
||||
|
||||
#define E1000_RX_BUFFER_SIZE 8192
|
||||
#define E1000_TX_BUFFER_SIZE 8192
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class E1000 : public NetworkInterface, public Interruptable
|
||||
{
|
||||
public:
|
||||
static bool probe(PCI::Device&);
|
||||
static BAN::ErrorOr<BAN::RefPtr<E1000>> create(PCI::Device&);
|
||||
~E1000();
|
||||
|
||||
virtual uint8_t* get_mac_address() override { return m_mac_address; }
|
||||
|
||||
virtual bool link_up() override { return m_link_up; }
|
||||
virtual int link_speed() override;
|
||||
|
||||
virtual void handle_irq() final override;
|
||||
|
||||
protected:
|
||||
E1000(PCI::Device& pci_device)
|
||||
: m_pci_device(pci_device)
|
||||
{ }
|
||||
BAN::ErrorOr<void> initialize();
|
||||
|
||||
virtual void detect_eeprom();
|
||||
virtual uint32_t eeprom_read(uint8_t addr);
|
||||
|
||||
uint32_t read32(uint16_t reg);
|
||||
void write32(uint16_t reg, uint32_t value);
|
||||
|
||||
virtual BAN::ErrorOr<void> send_raw_bytes(BAN::ConstByteSpan) override;
|
||||
|
||||
private:
|
||||
BAN::ErrorOr<void> read_mac_address();
|
||||
|
||||
BAN::ErrorOr<void> initialize_rx();
|
||||
BAN::ErrorOr<void> initialize_tx();
|
||||
|
||||
void enable_link();
|
||||
BAN::ErrorOr<void> enable_interrupt();
|
||||
|
||||
void handle_receive();
|
||||
|
||||
protected:
|
||||
PCI::Device& m_pci_device;
|
||||
BAN::UniqPtr<PCI::BarRegion> m_bar_region;
|
||||
bool m_has_eerprom { false };
|
||||
|
||||
private:
|
||||
BAN::UniqPtr<DMARegion> m_rx_buffer_region;
|
||||
BAN::UniqPtr<DMARegion> m_tx_buffer_region;
|
||||
BAN::UniqPtr<DMARegion> m_rx_descriptor_region;
|
||||
BAN::UniqPtr<DMARegion> m_tx_descriptor_region;
|
||||
|
||||
uint8_t m_mac_address[6] {};
|
||||
uint16_t m_rx_current {};
|
||||
uint16_t m_tx_current {};
|
||||
void* m_rx_buffers[E1000_RX_DESCRIPTOR_COUNT] {};
|
||||
void* m_tx_buffers[E1000_TX_DESCRIPTOR_COUNT] {};
|
||||
bool m_link_up { false };
|
||||
|
||||
friend class BAN::RefPtr<E1000>;
|
||||
};
|
||||
|
||||
}
|
||||
27
kernel/include/kernel/Networking/E1000/E1000E.h
Normal file
27
kernel/include/kernel/Networking/E1000/E1000E.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/Networking/E1000/E1000.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class E1000E final : public E1000
|
||||
{
|
||||
public:
|
||||
static bool probe(PCI::Device&);
|
||||
static BAN::ErrorOr<BAN::RefPtr<E1000E>> create(PCI::Device&);
|
||||
|
||||
protected:
|
||||
virtual void detect_eeprom() override;
|
||||
virtual uint32_t eeprom_read(uint8_t addr) override;
|
||||
|
||||
private:
|
||||
E1000E(PCI::Device& pci_device)
|
||||
: E1000(pci_device)
|
||||
{ }
|
||||
|
||||
private:
|
||||
friend class BAN::RefPtr<E1000E>;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Errors.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class NetworkDriver
|
||||
{
|
||||
public:
|
||||
virtual ~NetworkDriver() {}
|
||||
|
||||
virtual uint8_t* get_mac_address() = 0;
|
||||
virtual BAN::ErrorOr<void> send_packet(const void* data, uint16_t len) = 0;
|
||||
|
||||
virtual bool link_up() = 0;
|
||||
virtual int link_speed() = 0;
|
||||
};
|
||||
|
||||
}
|
||||
40
kernel/include/kernel/Networking/NetworkInterface.h
Normal file
40
kernel/include/kernel/Networking/NetworkInterface.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Errors.h>
|
||||
#include <BAN/ByteSpan.h>
|
||||
#include <kernel/Device/Device.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class NetworkInterface : public CharacterDevice
|
||||
{
|
||||
public:
|
||||
enum class Type
|
||||
{
|
||||
Ethernet,
|
||||
};
|
||||
|
||||
public:
|
||||
NetworkInterface();
|
||||
virtual ~NetworkInterface() {}
|
||||
|
||||
virtual uint8_t* get_mac_address() = 0;
|
||||
|
||||
virtual bool link_up() = 0;
|
||||
virtual int link_speed() = 0;
|
||||
|
||||
virtual dev_t rdev() const override { return m_rdev; }
|
||||
virtual BAN::StringView name() const override { return m_name; }
|
||||
|
||||
protected:
|
||||
virtual BAN::ErrorOr<void> send_raw_bytes(BAN::ConstByteSpan) = 0;
|
||||
|
||||
private:
|
||||
const Type m_type;
|
||||
|
||||
const dev_t m_rdev;
|
||||
char m_name[10];
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user