1000th COMMIT: Kernel: Add basic E1000 driver
This driver is only capable to read mac address and enable and read link status
This commit is contained in:
parent
5fae3cec2a
commit
14a608effd
|
@ -38,6 +38,7 @@ set(KERNEL_SOURCES
|
||||||
kernel/Memory/kmalloc.cpp
|
kernel/Memory/kmalloc.cpp
|
||||||
kernel/Memory/PhysicalRange.cpp
|
kernel/Memory/PhysicalRange.cpp
|
||||||
kernel/Memory/VirtualRange.cpp
|
kernel/Memory/VirtualRange.cpp
|
||||||
|
kernel/Networking/E1000.cpp
|
||||||
kernel/OpenFileDescriptorSet.cpp
|
kernel/OpenFileDescriptorSet.cpp
|
||||||
kernel/Panic.cpp
|
kernel/Panic.cpp
|
||||||
kernel/PCI.cpp
|
kernel/PCI.cpp
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/UniqPtr.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:
|
||||||
|
static BAN::ErrorOr<BAN::UniqPtr<E1000>> create(const PCIDevice&);
|
||||||
|
~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;
|
||||||
|
|
||||||
|
private:
|
||||||
|
E1000() = default;
|
||||||
|
BAN::ErrorOr<void> initialize(const PCIDevice&);
|
||||||
|
|
||||||
|
static void interrupt_handler();
|
||||||
|
|
||||||
|
void write32(uint16_t reg, uint32_t value);
|
||||||
|
uint32_t read32(uint16_t reg);
|
||||||
|
|
||||||
|
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();
|
||||||
|
void enable_interrupts();
|
||||||
|
|
||||||
|
void handle_receive();
|
||||||
|
|
||||||
|
private:
|
||||||
|
PCIDevice::BarType m_bar_type {};
|
||||||
|
uint64_t m_bar_addr {};
|
||||||
|
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,20 @@
|
||||||
|
#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;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -7,6 +7,14 @@ namespace Kernel
|
||||||
|
|
||||||
class PCIDevice
|
class PCIDevice
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
enum class BarType
|
||||||
|
{
|
||||||
|
INVAL,
|
||||||
|
MEM,
|
||||||
|
IO,
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PCIDevice(uint8_t, uint8_t, uint8_t);
|
PCIDevice(uint8_t, uint8_t, uint8_t);
|
||||||
|
|
||||||
|
@ -24,6 +32,9 @@ namespace Kernel
|
||||||
uint8_t subclass() const { return m_subclass; }
|
uint8_t subclass() const { return m_subclass; }
|
||||||
uint8_t prog_if() const { return m_prog_if; }
|
uint8_t prog_if() const { return m_prog_if; }
|
||||||
|
|
||||||
|
BarType read_bar_type(uint8_t) const;
|
||||||
|
uint64_t read_bar_address(uint8_t) const;
|
||||||
|
|
||||||
void enable_bus_mastering() const;
|
void enable_bus_mastering() const;
|
||||||
void disable_bus_mastering() const;
|
void disable_bus_mastering() const;
|
||||||
|
|
||||||
|
@ -41,6 +52,8 @@ namespace Kernel
|
||||||
uint8_t m_class_code;
|
uint8_t m_class_code;
|
||||||
uint8_t m_subclass;
|
uint8_t m_subclass;
|
||||||
uint8_t m_prog_if;
|
uint8_t m_prog_if;
|
||||||
|
|
||||||
|
uint8_t m_header_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PCI
|
class PCI
|
||||||
|
|
|
@ -0,0 +1,381 @@
|
||||||
|
#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 E1000_GENERAL_MEM_SIZE (128 * 1024)
|
||||||
|
|
||||||
|
#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));
|
||||||
|
|
||||||
|
BAN::ErrorOr<BAN::UniqPtr<E1000>> E1000::create(const PCIDevice& 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()
|
||||||
|
{
|
||||||
|
if (m_bar_type == PCIDevice::BarType::MEM && m_bar_addr)
|
||||||
|
PageTable::kernel().unmap_range(m_bar_addr & PAGE_ADDR_MASK, E1000_GENERAL_MEM_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> E1000::initialize(const PCIDevice& pci_device)
|
||||||
|
{
|
||||||
|
m_bar_type = pci_device.read_bar_type(0);
|
||||||
|
if (m_bar_type == PCIDevice::BarType::INVAL)
|
||||||
|
{
|
||||||
|
dwarnln("invalid bar0 type");
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_bar_type == PCIDevice::BarType::MEM)
|
||||||
|
{
|
||||||
|
uint64_t bar_addr = pci_device.read_bar_address(0);
|
||||||
|
|
||||||
|
vaddr_t page_vaddr = PageTable::kernel().reserve_free_contiguous_pages(E1000_GENERAL_MEM_SIZE / PAGE_SIZE, KERNEL_OFFSET);
|
||||||
|
paddr_t page_paddr = bar_addr & PAGE_ADDR_MASK;
|
||||||
|
PageTable::kernel().map_range_at(page_paddr, page_vaddr, E1000_GENERAL_MEM_SIZE, PageTable::Flags::CacheDisable | PageTable::Flags::ReadWrite | PageTable::Flags::Present);
|
||||||
|
|
||||||
|
m_bar_addr = page_vaddr + (bar_addr % PAGE_SIZE);
|
||||||
|
}
|
||||||
|
else if (m_bar_type == PCIDevice::BarType::IO)
|
||||||
|
{
|
||||||
|
m_bar_addr = pci_device.read_bar_address(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pci_device.enable_bus_mastering();
|
||||||
|
|
||||||
|
detect_eeprom();
|
||||||
|
|
||||||
|
TRY(read_mac_address());
|
||||||
|
|
||||||
|
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]
|
||||||
|
);
|
||||||
|
|
||||||
|
initialize_rx();
|
||||||
|
initialize_tx();
|
||||||
|
|
||||||
|
enable_link();
|
||||||
|
enable_interrupts();
|
||||||
|
|
||||||
|
dprintln(" link up: {}", link_up());
|
||||||
|
if (link_up())
|
||||||
|
dprintln(" link speed: {} Mbps", link_speed());
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void E1000::write32(uint16_t reg, uint32_t value)
|
||||||
|
{
|
||||||
|
switch (m_bar_type)
|
||||||
|
{
|
||||||
|
case PCIDevice::BarType::MEM:
|
||||||
|
MMIO::write32(m_bar_addr + reg, value);
|
||||||
|
break;
|
||||||
|
case PCIDevice::BarType::IO:
|
||||||
|
IO::outl(m_bar_addr, reg);
|
||||||
|
IO::outl(m_bar_addr + 4, value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t E1000::read32(uint16_t reg)
|
||||||
|
{
|
||||||
|
uint32_t result = 0;
|
||||||
|
switch (m_bar_type)
|
||||||
|
{
|
||||||
|
case PCIDevice::BarType::MEM:
|
||||||
|
result = MMIO::read32(m_bar_addr + reg);
|
||||||
|
break;
|
||||||
|
case PCIDevice::BarType::IO:
|
||||||
|
IO::outl(m_bar_addr, reg);
|
||||||
|
result = IO::inl(m_bar_addr + 4);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
#include <kernel/IO.h>
|
#include <kernel/IO.h>
|
||||||
|
#include <kernel/Networking/E1000.h>
|
||||||
#include <kernel/PCI.h>
|
#include <kernel/PCI.h>
|
||||||
#include <kernel/Storage/ATAController.h>
|
#include <kernel/Storage/ATAController.h>
|
||||||
|
|
||||||
|
@ -105,7 +106,7 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
case 0x01:
|
case 0x01:
|
||||||
if (auto res = ATAController::create(pci_device); res.is_error())
|
if (auto res = ATAController::create(pci_device); res.is_error())
|
||||||
dprintln("{}", res.error());
|
dprintln("ATA: {}", res.error());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dprintln("unsupported storage device (pci {2H}.{2H}.{2H})", pci_device.class_code(), pci_device.subclass(), pci_device.prog_if());
|
dprintln("unsupported storage device (pci {2H}.{2H}.{2H})", pci_device.class_code(), pci_device.subclass(), pci_device.prog_if());
|
||||||
|
@ -113,6 +114,20 @@ namespace Kernel
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 0x02:
|
||||||
|
{
|
||||||
|
switch (pci_device.subclass())
|
||||||
|
{
|
||||||
|
case 0x00:
|
||||||
|
if (auto res = E1000::create(pci_device); res.is_error())
|
||||||
|
dprintln("E1000: {}", res.error());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dprintln("unsupported ethernet device (pci {2H}.{2H}.{2H})", pci_device.class_code(), pci_device.subclass(), pci_device.prog_if());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -126,6 +141,7 @@ namespace Kernel
|
||||||
m_class_code = (uint8_t)(type >> 8);
|
m_class_code = (uint8_t)(type >> 8);
|
||||||
m_subclass = (uint8_t)(type);
|
m_subclass = (uint8_t)(type);
|
||||||
m_prog_if = read_byte(0x09);
|
m_prog_if = read_byte(0x09);
|
||||||
|
m_header_type = read_byte(0x0E);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t PCIDevice::read_dword(uint8_t offset) const
|
uint32_t PCIDevice::read_dword(uint8_t offset) const
|
||||||
|
@ -153,6 +169,33 @@ namespace Kernel
|
||||||
write_config_dword(m_bus, m_dev, m_func, offset, value);
|
write_config_dword(m_bus, m_dev, m_func, offset, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PCIDevice::BarType PCIDevice::read_bar_type(uint8_t bar) const
|
||||||
|
{
|
||||||
|
ASSERT(m_header_type == 0x00);
|
||||||
|
ASSERT(bar <= 5);
|
||||||
|
|
||||||
|
uint32_t type = read_dword(0x10 + bar * 4) & 0b111;
|
||||||
|
if (type & 1)
|
||||||
|
return BarType::IO;
|
||||||
|
type >>= 1;
|
||||||
|
if (type == 0x0 || type == 0x2)
|
||||||
|
return BarType::MEM;
|
||||||
|
return BarType::INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t PCIDevice::read_bar_address(uint8_t bar) const
|
||||||
|
{
|
||||||
|
ASSERT(m_header_type == 0x00);
|
||||||
|
ASSERT(bar <= 5);
|
||||||
|
|
||||||
|
uint64_t address = read_dword(0x10 + bar * 4);
|
||||||
|
if (address & 1)
|
||||||
|
return address & 0xFFFFFFFC;
|
||||||
|
if ((address & 0b110) == 0b100)
|
||||||
|
address |= (uint64_t)read_dword(0x10 + bar * 4 + 4) << 32;
|
||||||
|
return address & 0xFFFFFFFFFFFFFFF0;
|
||||||
|
}
|
||||||
|
|
||||||
void PCIDevice::enable_bus_mastering() const
|
void PCIDevice::enable_bus_mastering() const
|
||||||
{
|
{
|
||||||
write_dword(0x04, read_dword(0x04) | 1u << 2);
|
write_dword(0x04, read_dword(0x04) | 1u << 2);
|
||||||
|
|
Loading…
Reference in New Issue