forked from Bananymous/banan-os
Kernel: Write simple working E1000 and E1000E drivers
This commit is contained in:
parent
7cb71ec6fb
commit
f4e86028d0
|
@ -49,7 +49,9 @@ set(KERNEL_SOURCES
|
|||
kernel/Memory/MemoryRegion.cpp
|
||||
kernel/Memory/PhysicalRange.cpp
|
||||
kernel/Memory/VirtualRange.cpp
|
||||
kernel/Networking/E1000.cpp
|
||||
kernel/Networking/E1000/E1000.cpp
|
||||
kernel/Networking/E1000/E1000E.cpp
|
||||
kernel/Networking/NetworkInterface.cpp
|
||||
kernel/OpenFileDescriptorSet.cpp
|
||||
kernel/Panic.cpp
|
||||
kernel/PCI.cpp
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
|
||||
}
|
|
@ -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));
|
||||
|
||||
}
|
|
@ -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>;
|
||||
};
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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];
|
||||
};
|
||||
|
||||
}
|
|
@ -1,374 +0,0 @@
|
|||
#include <kernel/IDT.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/IO.h>
|
||||
#include <kernel/Memory/PageTable.h>
|
||||
#include <kernel/MMIO.h>
|
||||
#include <kernel/Networking/E1000.h>
|
||||
|
||||
#define DEBUG_E1000 1
|
||||
|
||||
#define E1000_REG_CTRL 0x0000
|
||||
#define E1000_REG_STATUS 0x0008
|
||||
#define E1000_REG_EEPROM 0x0014
|
||||
#define E1000_REG_INT_CAUSE_READ 0x00C0
|
||||
#define E1000_REG_INT_RATE 0x00C4
|
||||
#define E1000_REG_INT_MASK_SET 0x00D0
|
||||
#define E1000_REG_INT_MASK_CLEAR 0x00D8
|
||||
#define E1000_REG_RCTRL 0x0100
|
||||
#define E1000_REG_RXDESCLO 0x2800
|
||||
#define E1000_REG_RXDESCHI 0x2804
|
||||
#define E1000_REG_RXDESCLEN 0x2808
|
||||
#define E1000_REG_RXDESCHEAD 0x2810
|
||||
#define E1000_REG_RXDESCTAIL 0x2818
|
||||
#define E1000_REG_TXDESCLO 0x3800
|
||||
#define E1000_REG_TXDESCHI 0x3804
|
||||
#define E1000_REG_TXDESCLEN 0x3808
|
||||
#define E1000_REG_TXDESCHEAD 0x3810
|
||||
#define E1000_REG_TXDESCTAIL 0x3818
|
||||
#define E1000_REG_TCTRL 0x0400
|
||||
#define E1000_REG_TIPG 0x0410
|
||||
|
||||
#define E1000_STATUS_LINK_UP 0x02
|
||||
#define E1000_STATUS_SPEED_MASK 0xC0
|
||||
#define E1000_STATUS_SPEED_10MB 0x00
|
||||
#define E1000_STATUS_SPEED_100MB 0x40
|
||||
#define E1000_STATUS_SPEED_1000MB1 0x80
|
||||
#define E1000_STATUS_SPEED_1000MB2 0xC0
|
||||
|
||||
#define E1000_CTRL_SET_LINK_UP 0x40
|
||||
|
||||
#define E1000_INT_TXDW (1 << 0)
|
||||
#define E1000_INT_TXQE (1 << 1)
|
||||
#define E1000_INT_LSC (1 << 2)
|
||||
#define E1000_INT_RXSEQ (1 << 3)
|
||||
#define E1000_INT_RXDMT0 (1 << 4)
|
||||
#define E1000_INT_RXO (1 << 6)
|
||||
#define E1000_INT_RXT0 (1 << 7)
|
||||
#define E1000_INT_MDAC (1 << 9)
|
||||
#define E1000_INT_RXCFG (1 << 10)
|
||||
#define E1000_INT_PHYINT (1 << 12)
|
||||
#define E1000_INT_TXD_LOW (1 << 15)
|
||||
#define E1000_INT_SRPD (1 << 16)
|
||||
|
||||
|
||||
#define E1000_TCTL_EN (1 << 1)
|
||||
#define E1000_TCTL_PSP (1 << 3)
|
||||
#define E1000_TCTL_CT_SHIFT 4
|
||||
#define E1000_TCTL_COLD_SHIFT 12
|
||||
#define E1000_TCTL_SWXOFF (1 << 22)
|
||||
#define E1000_TCTL_RTLC (1 << 24)
|
||||
|
||||
#define E1000_RCTL_EN (1 << 1)
|
||||
#define E1000_RCTL_SBP (1 << 2)
|
||||
#define E1000_RCTL_UPE (1 << 3)
|
||||
#define E1000_RCTL_MPE (1 << 4)
|
||||
#define E1000_RCTL_LPE (1 << 5)
|
||||
#define E1000_RCTL_LBM_NONE (0 << 6)
|
||||
#define E1000_RCTL_LBM_PHY (3 << 6)
|
||||
#define E1000_RTCL_RDMTS_HALF (0 << 8)
|
||||
#define E1000_RTCL_RDMTS_QUARTER (1 << 8)
|
||||
#define E1000_RTCL_RDMTS_EIGHTH (2 << 8)
|
||||
#define E1000_RCTL_MO_36 (0 << 12)
|
||||
#define E1000_RCTL_MO_35 (1 << 12)
|
||||
#define E1000_RCTL_MO_34 (2 << 12)
|
||||
#define E1000_RCTL_MO_32 (3 << 12)
|
||||
#define E1000_RCTL_BAM (1 << 15)
|
||||
#define E1000_RCTL_VFE (1 << 18)
|
||||
#define E1000_RCTL_CFIEN (1 << 19)
|
||||
#define E1000_RCTL_CFI (1 << 20)
|
||||
#define E1000_RCTL_DPF (1 << 22)
|
||||
#define E1000_RCTL_PMCF (1 << 23)
|
||||
#define E1000_RCTL_SECRC (1 << 26)
|
||||
|
||||
#define E1000_RCTL_BSIZE_256 (3 << 16)
|
||||
#define E1000_RCTL_BSIZE_512 (2 << 16)
|
||||
#define E1000_RCTL_BSIZE_1024 (1 << 16)
|
||||
#define E1000_RCTL_BSIZE_2048 (0 << 16)
|
||||
#define E1000_RCTL_BSIZE_4096 ((3 << 16) | (1 << 25))
|
||||
#define E1000_RCTL_BSIZE_8192 ((2 << 16) | (1 << 25))
|
||||
#define E1000_RCTL_BSIZE_16384 ((1 << 16) | (1 << 25))
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
struct e1000_rx_desc
|
||||
{
|
||||
volatile uint64_t addr;
|
||||
volatile uint16_t length;
|
||||
volatile uint16_t checksum;
|
||||
volatile uint8_t status;
|
||||
volatile uint8_t errors;
|
||||
volatile uint16_t special;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct e1000_tx_desc
|
||||
{
|
||||
volatile uint64_t addr;
|
||||
volatile uint16_t length;
|
||||
volatile uint8_t cso;
|
||||
volatile uint8_t cmd;
|
||||
volatile uint8_t status;
|
||||
volatile uint8_t css;
|
||||
volatile uint16_t special;
|
||||
} __attribute__((packed));
|
||||
|
||||
// https://www.intel.com/content/dam/doc/manual/pci-pci-x-family-gbe-controllers-software-dev-manual.pdf (section 5.2)
|
||||
bool E1000::probe(PCI::Device& pci_device)
|
||||
{
|
||||
// Intel device
|
||||
if (pci_device.vendor_id() != 0x8086)
|
||||
return false;
|
||||
|
||||
switch (pci_device.device_id())
|
||||
{
|
||||
case 0x1019:
|
||||
case 0x101A:
|
||||
case 0x1010:
|
||||
case 0x1012:
|
||||
case 0x101D:
|
||||
case 0x1079:
|
||||
case 0x107A:
|
||||
case 0x107B:
|
||||
case 0x100F:
|
||||
case 0x1011:
|
||||
case 0x1026:
|
||||
case 0x1027:
|
||||
case 0x1028:
|
||||
case 0x1107:
|
||||
case 0x1112:
|
||||
case 0x1013:
|
||||
case 0x1018:
|
||||
case 0x1076:
|
||||
case 0x1077:
|
||||
case 0x1078:
|
||||
case 0x1017:
|
||||
case 0x1016:
|
||||
case 0x100e:
|
||||
case 0x1015:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::UniqPtr<E1000>> E1000::create(PCI::Device& pci_device)
|
||||
{
|
||||
E1000* e1000 = new E1000();
|
||||
ASSERT(e1000);
|
||||
if (auto ret = e1000->initialize(pci_device); ret.is_error())
|
||||
{
|
||||
delete e1000;
|
||||
return ret.release_error();
|
||||
}
|
||||
return BAN::UniqPtr<E1000>::adopt(e1000);
|
||||
}
|
||||
|
||||
E1000::~E1000()
|
||||
{
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> E1000::initialize(PCI::Device& pci_device)
|
||||
{
|
||||
m_bar_region = TRY(pci_device.allocate_bar_region(0));
|
||||
pci_device.enable_bus_mastering();
|
||||
|
||||
detect_eeprom();
|
||||
|
||||
TRY(read_mac_address());
|
||||
|
||||
|
||||
initialize_rx();
|
||||
initialize_tx();
|
||||
|
||||
enable_link();
|
||||
enable_interrupts();
|
||||
|
||||
#if DEBUG_E1000
|
||||
dprintln("E1000 at PCI {}:{}.{}", pci_device.bus(), pci_device.dev(), pci_device.func());
|
||||
dprintln(" MAC: {2H}:{2H}:{2H}:{2H}:{2H}:{2H}",
|
||||
m_mac_address[0],
|
||||
m_mac_address[1],
|
||||
m_mac_address[2],
|
||||
m_mac_address[3],
|
||||
m_mac_address[4],
|
||||
m_mac_address[5]
|
||||
);
|
||||
dprintln(" link up: {}", link_up());
|
||||
if (link_up())
|
||||
dprintln(" link speed: {} Mbps", link_speed());
|
||||
#endif
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void E1000::write32(uint16_t reg, uint32_t value)
|
||||
{
|
||||
m_bar_region->write32(reg, value);
|
||||
}
|
||||
|
||||
uint32_t E1000::read32(uint16_t reg)
|
||||
{
|
||||
return m_bar_region->read32(reg);
|
||||
}
|
||||
|
||||
void E1000::detect_eeprom()
|
||||
{
|
||||
m_has_eerprom = false;
|
||||
write32(E1000_REG_EEPROM, 0x01);
|
||||
for (int i = 0; i < 1000 && !m_has_eerprom; i++)
|
||||
if (read32(E1000_REG_EEPROM) & 0x10)
|
||||
m_has_eerprom = true;
|
||||
}
|
||||
|
||||
uint32_t E1000::eeprom_read(uint8_t address)
|
||||
{
|
||||
uint32_t tmp = 0;
|
||||
if (m_has_eerprom)
|
||||
{
|
||||
write32(E1000_REG_EEPROM, ((uint32_t)address << 8) | 1);
|
||||
while (!((tmp = read32(E1000_REG_EEPROM)) & (1 << 4)))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
write32(E1000_REG_EEPROM, ((uint32_t)address << 2) | 1);
|
||||
while (!((tmp = read32(E1000_REG_EEPROM)) & (1 << 1)))
|
||||
continue;
|
||||
}
|
||||
return (tmp >> 16) & 0xFFFF;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> E1000::read_mac_address()
|
||||
{
|
||||
if (m_has_eerprom)
|
||||
{
|
||||
uint32_t temp = eeprom_read(0);
|
||||
m_mac_address[0] = temp;
|
||||
m_mac_address[1] = temp >> 8;
|
||||
|
||||
temp = eeprom_read(1);
|
||||
m_mac_address[2] = temp;
|
||||
m_mac_address[3] = temp >> 8;
|
||||
|
||||
temp = eeprom_read(2);
|
||||
m_mac_address[4] = temp;
|
||||
m_mac_address[5] = temp >> 8;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (read32(0x5400) == 0)
|
||||
{
|
||||
dwarnln("no mac address");
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
m_mac_address[i] = (uint8_t)read32(0x5400 + i * 8);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void E1000::initialize_rx()
|
||||
{
|
||||
uint8_t* ptr = (uint8_t*)kmalloc(sizeof(e1000_rx_desc) * E1000_NUM_RX_DESC + 16, 16, true);
|
||||
ASSERT(ptr);
|
||||
|
||||
e1000_rx_desc* descs = (e1000_rx_desc*)ptr;
|
||||
for (int i = 0; i < E1000_NUM_RX_DESC; i++)
|
||||
{
|
||||
// FIXME
|
||||
m_rx_descs[i] = &descs[i];
|
||||
m_rx_descs[i]->addr = 0;
|
||||
m_rx_descs[i]->status = 0;
|
||||
}
|
||||
|
||||
write32(E1000_REG_RXDESCLO, (uintptr_t)ptr >> 32);
|
||||
write32(E1000_REG_RXDESCHI, (uintptr_t)ptr & 0xFFFFFFFF);
|
||||
write32(E1000_REG_RXDESCLEN, E1000_NUM_RX_DESC * sizeof(e1000_rx_desc));
|
||||
write32(E1000_REG_RXDESCHEAD, 0);
|
||||
write32(E1000_REG_RXDESCTAIL, E1000_NUM_RX_DESC - 1);
|
||||
|
||||
m_rx_current = 0;
|
||||
|
||||
uint32_t rctrl = 0;
|
||||
rctrl |= E1000_RCTL_EN;
|
||||
rctrl |= E1000_RCTL_SBP;
|
||||
rctrl |= E1000_RCTL_UPE;
|
||||
rctrl |= E1000_RCTL_MPE;
|
||||
rctrl |= E1000_RCTL_LBM_NONE;
|
||||
rctrl |= E1000_RTCL_RDMTS_HALF;
|
||||
rctrl |= E1000_RCTL_BAM;
|
||||
rctrl |= E1000_RCTL_SECRC;
|
||||
rctrl |= E1000_RCTL_BSIZE_8192;
|
||||
|
||||
write32(E1000_REG_RCTRL, rctrl);
|
||||
}
|
||||
|
||||
void E1000::initialize_tx()
|
||||
{
|
||||
auto* ptr = (uint8_t*)kmalloc(sizeof(e1000_tx_desc) * E1000_NUM_TX_DESC + 16, 16, true);
|
||||
ASSERT(ptr);
|
||||
|
||||
auto* descs = (e1000_tx_desc*)ptr;
|
||||
for(int i = 0; i < E1000_NUM_TX_DESC; i++)
|
||||
{
|
||||
// FIXME
|
||||
m_tx_descs[i] = &descs[i];
|
||||
m_tx_descs[i]->addr = 0;
|
||||
m_tx_descs[i]->cmd = 0;
|
||||
}
|
||||
|
||||
write32(E1000_REG_TXDESCHI, (uintptr_t)ptr >> 32);
|
||||
write32(E1000_REG_TXDESCLO, (uintptr_t)ptr & 0xFFFFFFFF);
|
||||
write32(E1000_REG_TXDESCLEN, E1000_NUM_TX_DESC * sizeof(e1000_tx_desc));
|
||||
write32(E1000_REG_TXDESCHEAD, 0);
|
||||
write32(E1000_REG_TXDESCTAIL, 0);
|
||||
|
||||
m_tx_current = 0;
|
||||
|
||||
write32(E1000_REG_TCTRL, read32(E1000_REG_TCTRL) | E1000_TCTL_EN | E1000_TCTL_PSP);
|
||||
write32(E1000_REG_TIPG, 0x0060200A);
|
||||
}
|
||||
|
||||
void E1000::enable_link()
|
||||
{
|
||||
write32(E1000_REG_CTRL, read32(E1000_REG_CTRL) | E1000_CTRL_SET_LINK_UP);
|
||||
m_link_up = !!(read32(E1000_REG_STATUS) & E1000_STATUS_LINK_UP);
|
||||
}
|
||||
|
||||
int E1000::link_speed()
|
||||
{
|
||||
if (!link_up())
|
||||
return 0;
|
||||
uint32_t speed = read32(E1000_REG_STATUS) & E1000_STATUS_SPEED_MASK;
|
||||
if (speed == E1000_STATUS_SPEED_10MB)
|
||||
return 10;
|
||||
if (speed == E1000_STATUS_SPEED_100MB)
|
||||
return 100;
|
||||
if (speed == E1000_STATUS_SPEED_1000MB1)
|
||||
return 1000;
|
||||
if (speed == E1000_STATUS_SPEED_1000MB2)
|
||||
return 1000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void E1000::enable_interrupts()
|
||||
{
|
||||
write32(E1000_REG_INT_RATE, 6000);
|
||||
write32(E1000_REG_INT_MASK_SET, E1000_INT_LSC | E1000_INT_RXT0 | E1000_INT_RXO);
|
||||
read32(E1000_REG_INT_CAUSE_READ);
|
||||
|
||||
// FIXME: implement PCI interrupt allocation
|
||||
//IDT::register_irq_handler(irq, E1000::interrupt_handler);
|
||||
//InterruptController::enable_irq(irq);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> E1000::send_packet(const void* data, uint16_t len)
|
||||
{
|
||||
(void)data;
|
||||
(void)len;
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,314 @@
|
|||
#include <kernel/FS/DevFS/FileSystem.h>
|
||||
#include <kernel/IDT.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/IO.h>
|
||||
#include <kernel/Memory/PageTable.h>
|
||||
#include <kernel/MMIO.h>
|
||||
#include <kernel/Networking/E1000/E1000.h>
|
||||
|
||||
#define DEBUG_E1000 1
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
// https://www.intel.com/content/dam/doc/manual/pci-pci-x-family-gbe-controllers-software-dev-manual.pdf (section 5.2)
|
||||
bool E1000::probe(PCI::Device& pci_device)
|
||||
{
|
||||
// Intel device
|
||||
if (pci_device.vendor_id() != 0x8086)
|
||||
return false;
|
||||
|
||||
switch (pci_device.device_id())
|
||||
{
|
||||
case 0x1019:
|
||||
case 0x101A:
|
||||
case 0x1010:
|
||||
case 0x1012:
|
||||
case 0x101D:
|
||||
case 0x1079:
|
||||
case 0x107A:
|
||||
case 0x107B:
|
||||
case 0x100F:
|
||||
case 0x1011:
|
||||
case 0x1026:
|
||||
case 0x1027:
|
||||
case 0x1028:
|
||||
case 0x1107:
|
||||
case 0x1112:
|
||||
case 0x1013:
|
||||
case 0x1018:
|
||||
case 0x1076:
|
||||
case 0x1077:
|
||||
case 0x1078:
|
||||
case 0x1017:
|
||||
case 0x1016:
|
||||
case 0x100e:
|
||||
case 0x1015:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<E1000>> E1000::create(PCI::Device& pci_device)
|
||||
{
|
||||
auto e1000 = TRY(BAN::RefPtr<E1000>::create(pci_device));
|
||||
TRY(e1000->initialize());
|
||||
return e1000;
|
||||
}
|
||||
|
||||
E1000::~E1000()
|
||||
{
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> E1000::initialize()
|
||||
{
|
||||
m_bar_region = TRY(m_pci_device.allocate_bar_region(0));
|
||||
m_pci_device.enable_bus_mastering();
|
||||
|
||||
detect_eeprom();
|
||||
TRY(read_mac_address());
|
||||
#if DEBUG_E1000
|
||||
dprintln("E1000 at PCI {}:{}.{}", m_pci_device.bus(), m_pci_device.dev(), m_pci_device.func());
|
||||
dprintln(" MAC: {2H}:{2H}:{2H}:{2H}:{2H}:{2H}",
|
||||
m_mac_address[0],
|
||||
m_mac_address[1],
|
||||
m_mac_address[2],
|
||||
m_mac_address[3],
|
||||
m_mac_address[4],
|
||||
m_mac_address[5]
|
||||
);
|
||||
#endif
|
||||
|
||||
TRY(initialize_rx());
|
||||
TRY(initialize_tx());
|
||||
|
||||
enable_link();
|
||||
TRY(enable_interrupt());
|
||||
|
||||
m_link_up = !!(read32(REG_STATUS) & STATUS_LU);
|
||||
|
||||
#if DEBUG_E1000
|
||||
dprintln(" link up: {}", link_up());
|
||||
if (link_up())
|
||||
{
|
||||
int speed = link_speed();
|
||||
dprintln(" link speed: {} Mbps", speed);
|
||||
}
|
||||
#endif
|
||||
|
||||
DevFileSystem::get().add_device(this);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void E1000::write32(uint16_t reg, uint32_t value)
|
||||
{
|
||||
m_bar_region->write32(reg, value);
|
||||
}
|
||||
|
||||
uint32_t E1000::read32(uint16_t reg)
|
||||
{
|
||||
return m_bar_region->read32(reg);
|
||||
}
|
||||
|
||||
void E1000::detect_eeprom()
|
||||
{
|
||||
m_has_eerprom = false;
|
||||
write32(REG_EERD, 0x01);
|
||||
for (int i = 0; i < 1000 && !m_has_eerprom; i++)
|
||||
if (read32(REG_EERD) & 0x10)
|
||||
m_has_eerprom = true;
|
||||
}
|
||||
|
||||
uint32_t E1000::eeprom_read(uint8_t address)
|
||||
{
|
||||
uint32_t tmp = 0;
|
||||
if (m_has_eerprom)
|
||||
{
|
||||
write32(REG_EERD, ((uint32_t)address << 8) | 1);
|
||||
while (!((tmp = read32(REG_EERD)) & (1 << 4)))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
write32(REG_EERD, ((uint32_t)address << 2) | 1);
|
||||
while (!((tmp = read32(REG_EERD)) & (1 << 1)))
|
||||
continue;
|
||||
}
|
||||
return (tmp >> 16) & 0xFFFF;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> E1000::read_mac_address()
|
||||
{
|
||||
if (m_has_eerprom)
|
||||
{
|
||||
uint32_t temp = eeprom_read(0);
|
||||
m_mac_address[0] = temp;
|
||||
m_mac_address[1] = temp >> 8;
|
||||
|
||||
temp = eeprom_read(1);
|
||||
m_mac_address[2] = temp;
|
||||
m_mac_address[3] = temp >> 8;
|
||||
|
||||
temp = eeprom_read(2);
|
||||
m_mac_address[4] = temp;
|
||||
m_mac_address[5] = temp >> 8;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (read32(0x5400) == 0)
|
||||
{
|
||||
dwarnln("no mac address");
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
m_mac_address[i] = (uint8_t)read32(0x5400 + i * 8);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> E1000::initialize_rx()
|
||||
{
|
||||
m_rx_buffer_region = TRY(DMARegion::create(E1000_RX_BUFFER_SIZE * E1000_RX_DESCRIPTOR_COUNT));
|
||||
m_rx_descriptor_region = TRY(DMARegion::create(sizeof(e1000_rx_desc) * E1000_RX_DESCRIPTOR_COUNT));
|
||||
|
||||
auto* rx_descriptors = reinterpret_cast<volatile e1000_rx_desc*>(m_rx_descriptor_region->vaddr());
|
||||
for (size_t i = 0; i < E1000_RX_DESCRIPTOR_COUNT; i++)
|
||||
{
|
||||
m_rx_buffers[i] = reinterpret_cast<void*>(m_rx_buffer_region->vaddr() + E1000_RX_BUFFER_SIZE * i);
|
||||
rx_descriptors[i].addr = m_rx_buffer_region->paddr() + E1000_RX_BUFFER_SIZE * i;
|
||||
rx_descriptors[i].status = 0;
|
||||
}
|
||||
|
||||
write32(REG_RDBAL0, m_rx_descriptor_region->paddr() & 0xFFFFFFFF);
|
||||
write32(REG_RDBAH0, m_rx_descriptor_region->paddr() >> 32);
|
||||
write32(REG_RDLEN0, E1000_RX_DESCRIPTOR_COUNT * sizeof(e1000_rx_desc));
|
||||
write32(REG_RDH0, 0);
|
||||
write32(REG_RDT0, E1000_RX_DESCRIPTOR_COUNT - 1);
|
||||
|
||||
uint32_t rctrl = 0;
|
||||
rctrl |= RCTL_EN;
|
||||
rctrl |= RCTL_SBP;
|
||||
rctrl |= RCTL_UPE;
|
||||
rctrl |= RCTL_MPE;
|
||||
rctrl |= RCTL_LBM_NORMAL;
|
||||
rctrl |= RCTL_RDMTS_1_2;
|
||||
rctrl |= RCTL_BAM;
|
||||
rctrl |= RCTL_SECRC;
|
||||
rctrl |= RCTL_BSIZE_8192;
|
||||
write32(REG_RCTL, rctrl);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> E1000::initialize_tx()
|
||||
{
|
||||
m_tx_buffer_region = TRY(DMARegion::create(E1000_TX_BUFFER_SIZE * E1000_TX_DESCRIPTOR_COUNT));
|
||||
m_tx_descriptor_region = TRY(DMARegion::create(sizeof(e1000_tx_desc) * E1000_TX_DESCRIPTOR_COUNT));
|
||||
|
||||
auto* tx_descriptors = reinterpret_cast<volatile e1000_tx_desc*>(m_tx_descriptor_region->vaddr());
|
||||
for (size_t i = 0; i < E1000_TX_DESCRIPTOR_COUNT; i++)
|
||||
{
|
||||
m_tx_buffers[i] = reinterpret_cast<void*>(m_tx_buffer_region->vaddr() + E1000_TX_BUFFER_SIZE * i);
|
||||
tx_descriptors[i].addr = m_tx_buffer_region->paddr() + E1000_TX_BUFFER_SIZE * i;
|
||||
tx_descriptors[i].cmd = 0;
|
||||
}
|
||||
|
||||
write32(REG_TDBAL, m_tx_descriptor_region->paddr() & 0xFFFFFFFF);
|
||||
write32(REG_TDBAH, m_tx_descriptor_region->paddr() >> 32);
|
||||
write32(REG_TDLEN, E1000_TX_DESCRIPTOR_COUNT * sizeof(e1000_tx_desc));
|
||||
write32(REG_TDH, 0);
|
||||
write32(REG_TDT, 0);
|
||||
|
||||
write32(REG_TCTL, TCTL_EN | TCTL_PSP);
|
||||
write32(REG_TIPG, 0x0060200A);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void E1000::enable_link()
|
||||
{
|
||||
write32(REG_CTRL, read32(REG_CTRL) | CTRL_SLU);
|
||||
}
|
||||
|
||||
int E1000::link_speed()
|
||||
{
|
||||
if (!link_up())
|
||||
return 0;
|
||||
uint32_t speed = read32(REG_STATUS) & STATUS_SPEED_MASK;
|
||||
if (speed == STATUS_SPEED_10MB)
|
||||
return 10;
|
||||
if (speed == STATUS_SPEED_100MB)
|
||||
return 100;
|
||||
if (speed == STATUS_SPEED_1000MB1)
|
||||
return 1000;
|
||||
if (speed == STATUS_SPEED_1000MB2)
|
||||
return 1000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> E1000::enable_interrupt()
|
||||
{
|
||||
write32(REG_ITR, 0x1000);
|
||||
|
||||
write32(REG_IVAR, 1 << 3);
|
||||
write32(REG_EITR, 0x1000);
|
||||
|
||||
write32(REG_IMS, IMC_RxQ0);
|
||||
read32(REG_ICR);
|
||||
|
||||
TRY(m_pci_device.reserve_irqs(1));
|
||||
set_irq(m_pci_device.get_irq(0));
|
||||
Interruptable::enable_interrupt();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> E1000::send_raw_bytes(BAN::ConstByteSpan buffer)
|
||||
{
|
||||
ASSERT_LTE(buffer.size(), E1000_TX_BUFFER_SIZE);
|
||||
|
||||
CriticalScope _;
|
||||
|
||||
size_t tx_current = read32(REG_TDT) % E1000_TX_DESCRIPTOR_COUNT;
|
||||
|
||||
auto* tx_buffer = reinterpret_cast<void*>(m_tx_buffer_region->vaddr() + E1000_TX_BUFFER_SIZE * tx_current);
|
||||
memcpy(tx_buffer, buffer.data(), buffer.size());
|
||||
|
||||
auto& descriptor = reinterpret_cast<volatile e1000_tx_desc*>(m_tx_descriptor_region->vaddr())[tx_current];
|
||||
descriptor.length = buffer.size();
|
||||
descriptor.status = 0;
|
||||
descriptor.cmd = CMD_EOP | CMD_IFCS | CMD_RS;
|
||||
|
||||
write32(REG_TDT, (tx_current + 1) % E1000_TX_DESCRIPTOR_COUNT);
|
||||
while (descriptor.status == 0)
|
||||
continue;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void E1000::handle_irq()
|
||||
{
|
||||
if (read32(REG_ICR) & ICR_RxQ0)
|
||||
return;
|
||||
|
||||
for (;;) {
|
||||
uint32_t rx_current = (read32(REG_RDT0) + 1) % E1000_RX_DESCRIPTOR_COUNT;
|
||||
|
||||
auto& descriptor = reinterpret_cast<volatile e1000_rx_desc*>(m_rx_descriptor_region->vaddr())[rx_current];
|
||||
if (!(descriptor.status & 1))
|
||||
break;
|
||||
ASSERT_LTE((uint16_t)descriptor.length, E1000_RX_BUFFER_SIZE);
|
||||
|
||||
// FIXME: do something with the packet :)
|
||||
dprintln("got {} byte packet", (uint16_t)descriptor.length);
|
||||
|
||||
descriptor.status = 0;
|
||||
write32(REG_RDT0, rx_current);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
#include <kernel/Networking/E1000/E1000E.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
|
||||
#define E1000E_VENDOR_INTEL 0x8086
|
||||
#define E1000E_DEVICE_82574 0x10D3
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
bool E1000E::probe(PCI::Device& pci_device)
|
||||
{
|
||||
if (pci_device.vendor_id() != E1000E_VENDOR_INTEL)
|
||||
return false;
|
||||
switch (pci_device.device_id())
|
||||
{
|
||||
case E1000E_DEVICE_82574:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<E1000E>> E1000E::create(PCI::Device& pci_device)
|
||||
{
|
||||
auto e1000e = TRY(BAN::RefPtr<E1000E>::create(pci_device));
|
||||
TRY(e1000e->initialize());
|
||||
return e1000e;
|
||||
}
|
||||
|
||||
void E1000E::detect_eeprom()
|
||||
{
|
||||
m_has_eerprom = true;
|
||||
}
|
||||
|
||||
uint32_t E1000E::eeprom_read(uint8_t addr)
|
||||
{
|
||||
uint32_t tmp;
|
||||
write32(REG_EERD, ((uint32_t)addr << 2) | 1);
|
||||
while (!((tmp = read32(REG_EERD)) & (1 << 1)))
|
||||
continue;
|
||||
return tmp >> 16;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
#include <kernel/FS/DevFS/FileSystem.h>
|
||||
#include <kernel/Networking/NetworkInterface.h>
|
||||
|
||||
#include <sys/sysmacros.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
static dev_t get_network_rdev_major()
|
||||
{
|
||||
static dev_t major = DevFileSystem::get().get_next_dev();
|
||||
return major;
|
||||
}
|
||||
|
||||
static dev_t get_network_rdev_minor()
|
||||
{
|
||||
static dev_t minor = 0;
|
||||
return minor++;
|
||||
}
|
||||
|
||||
NetworkInterface::NetworkInterface()
|
||||
: CharacterDevice(0400, 0, 0)
|
||||
, m_type(Type::Ethernet)
|
||||
, m_rdev(makedev(get_network_rdev_major(), get_network_rdev_minor()))
|
||||
{
|
||||
ASSERT(minor(m_rdev) < 10);
|
||||
ASSERT(m_type == Type::Ethernet);
|
||||
|
||||
strcpy(m_name, "ethx");
|
||||
m_name[3] = minor(m_rdev) + '0';
|
||||
}
|
||||
|
||||
}
|
|
@ -2,7 +2,8 @@
|
|||
#include <kernel/IO.h>
|
||||
#include <kernel/Memory/PageTable.h>
|
||||
#include <kernel/MMIO.h>
|
||||
#include <kernel/Networking/E1000.h>
|
||||
#include <kernel/Networking/E1000/E1000.h>
|
||||
#include <kernel/Networking/E1000/E1000E.h>
|
||||
#include <kernel/PCI.h>
|
||||
#include <kernel/Storage/ATA/AHCI/Controller.h>
|
||||
#include <kernel/Storage/ATA/ATAController.h>
|
||||
|
@ -187,11 +188,22 @@ namespace Kernel::PCI
|
|||
{
|
||||
case 0x00:
|
||||
if (E1000::probe(pci_device))
|
||||
{
|
||||
if (auto res = E1000::create(pci_device); res.is_error())
|
||||
dprintln("E1000: {}", res.error());
|
||||
break;
|
||||
}
|
||||
if (E1000E::probe(pci_device))
|
||||
{
|
||||
if (auto res = E1000E::create(pci_device); res.is_error())
|
||||
dprintln("E1000E: {}", res.error());
|
||||
break;
|
||||
}
|
||||
// fall through
|
||||
default:
|
||||
dprintln("unsupported ethernet device (pci {2H}.{2H}.{2H})", pci_device.class_code(), pci_device.subclass(), pci_device.prog_if());
|
||||
dprintln("unsupported network controller (pci {2H}.{2H}.{2H})", pci_device.class_code(), pci_device.subclass(), pci_device.prog_if());
|
||||
dprintln(" vendor id: {4H}", pci_device.vendor_id());
|
||||
dprintln(" device id: {4H}", pci_device.device_id());
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue