mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-26 09:30:24 +00:00
Kernel/Net: Support Intel 82574 adapter
We call it E1000E, because the layout for these cards is somewhat not the same like E1000 supported cards. Also, this card supports advanced features that are not supported on 8254x cards.
This commit is contained in:
parent
2e2201e8e1
commit
c6480a0426
Notes:
sideshowbarker
2024-07-18 12:32:31 +09:00
Author: https://github.com/supercomputer7 Commit: https://github.com/SerenityOS/serenity/commit/c6480a04264 Pull-request: https://github.com/SerenityOS/serenity/pull/7762 Reviewed-by: https://github.com/alimpfard ✅
8 changed files with 200 additions and 20 deletions
|
@ -115,6 +115,7 @@ set(KERNEL_SOURCES
|
|||
KString.cpp
|
||||
KSyms.cpp
|
||||
Lock.cpp
|
||||
Net/E1000ENetworkAdapter.cpp
|
||||
Net/E1000NetworkAdapter.cpp
|
||||
Net/IPv4Socket.cpp
|
||||
Net/LocalSocket.cpp
|
||||
|
|
|
@ -46,6 +46,10 @@
|
|||
#cmakedefine01 E1000_DEBUG
|
||||
#endif
|
||||
|
||||
#ifndef E1000E_DEBUG
|
||||
#cmakedefine01 E1000E_DEBUG
|
||||
#endif
|
||||
|
||||
#ifndef ETHERNET_DEBUG
|
||||
#cmakedefine01 ETHERNET_DEBUG
|
||||
#endif
|
||||
|
|
108
Kernel/Net/E1000ENetworkAdapter.cpp
Normal file
108
Kernel/Net/E1000ENetworkAdapter.cpp
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/MACAddress.h>
|
||||
#include <Kernel/Debug.h>
|
||||
#include <Kernel/Net/E1000ENetworkAdapter.h>
|
||||
#include <Kernel/PCI/IDs.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
#define REG_EEPROM 0x0014
|
||||
|
||||
static bool is_valid_device_id(u16 device_id)
|
||||
{
|
||||
switch (device_id) {
|
||||
case 0x10D3: // 82574
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT RefPtr<E1000ENetworkAdapter> E1000ENetworkAdapter::try_to_initialize(PCI::Address address)
|
||||
{
|
||||
auto id = PCI::get_id(address);
|
||||
if (id.vendor_id != (u16)PCIVendorID::Intel)
|
||||
return {};
|
||||
if (!is_valid_device_id(id.device_id))
|
||||
return {};
|
||||
u8 irq = PCI::get_interrupt_line(address);
|
||||
auto adapter = adopt_ref_if_nonnull(new E1000ENetworkAdapter(address, irq));
|
||||
if (!adapter)
|
||||
return {};
|
||||
if (adapter->initialize())
|
||||
return adapter;
|
||||
return {};
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT bool E1000ENetworkAdapter::initialize()
|
||||
{
|
||||
dmesgln("E1000e: Found @ {}", pci_address());
|
||||
|
||||
m_io_base = IOAddress(PCI::get_BAR2(pci_address()) & ~1);
|
||||
|
||||
enable_bus_mastering(pci_address());
|
||||
|
||||
size_t mmio_base_size = PCI::get_BAR_space_size(pci_address(), 0);
|
||||
m_mmio_region = MM.allocate_kernel_region(PhysicalAddress(page_base_of(PCI::get_BAR0(pci_address()))), page_round_up(mmio_base_size), "E1000e MMIO", Region::Access::Read | Region::Access::Write, Region::Cacheable::No);
|
||||
if (!m_mmio_region)
|
||||
return false;
|
||||
m_mmio_base = m_mmio_region->vaddr();
|
||||
m_use_mmio = true;
|
||||
m_interrupt_line = PCI::get_interrupt_line(pci_address());
|
||||
dmesgln("E1000e: port base: {}", m_io_base);
|
||||
dmesgln("E1000e: MMIO base: {}", PhysicalAddress(PCI::get_BAR0(pci_address()) & 0xfffffffc));
|
||||
dmesgln("E1000e: MMIO base size: {} bytes", mmio_base_size);
|
||||
dmesgln("E1000e: Interrupt line: {}", m_interrupt_line);
|
||||
detect_eeprom();
|
||||
dmesgln("E1000e: Has EEPROM? {}", m_has_eeprom);
|
||||
read_mac_address();
|
||||
const auto& mac = mac_address();
|
||||
dmesgln("E1000e: MAC address: {}", mac.to_string());
|
||||
|
||||
initialize_rx_descriptors();
|
||||
initialize_tx_descriptors();
|
||||
|
||||
setup_link();
|
||||
setup_interrupts();
|
||||
return true;
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT E1000ENetworkAdapter::E1000ENetworkAdapter(PCI::Address address, u8 irq)
|
||||
: E1000NetworkAdapter(address, irq)
|
||||
{
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT E1000ENetworkAdapter::~E1000ENetworkAdapter()
|
||||
{
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT void E1000ENetworkAdapter::detect_eeprom()
|
||||
{
|
||||
// FIXME: Try to find a way to detect if EEPROM exists instead of assuming it is
|
||||
m_has_eeprom = true;
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT u32 E1000ENetworkAdapter::read_eeprom(u8 address)
|
||||
{
|
||||
VERIFY(m_has_eeprom);
|
||||
u16 data = 0;
|
||||
u32 tmp = 0;
|
||||
if (m_has_eeprom) {
|
||||
out32(REG_EEPROM, ((u32)address << 2) | 1);
|
||||
while (!((tmp = in32(REG_EEPROM)) & (1 << 1)))
|
||||
;
|
||||
} else {
|
||||
out32(REG_EEPROM, ((u32)address << 2) | 1);
|
||||
while (!((tmp = in32(REG_EEPROM)) & (1 << 1)))
|
||||
;
|
||||
}
|
||||
data = (tmp >> 16) & 0xffff;
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
40
Kernel/Net/E1000ENetworkAdapter.h
Normal file
40
Kernel/Net/E1000ENetworkAdapter.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/NonnullOwnPtrVector.h>
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <Kernel/IO.h>
|
||||
#include <Kernel/Interrupts/IRQHandler.h>
|
||||
#include <Kernel/Net/E1000NetworkAdapter.h>
|
||||
#include <Kernel/Net/NetworkAdapter.h>
|
||||
#include <Kernel/PCI/Access.h>
|
||||
#include <Kernel/PCI/Device.h>
|
||||
#include <Kernel/Random.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class E1000ENetworkAdapter final
|
||||
: public E1000NetworkAdapter {
|
||||
public:
|
||||
static RefPtr<E1000ENetworkAdapter> try_to_initialize(PCI::Address);
|
||||
|
||||
virtual bool initialize() override;
|
||||
|
||||
virtual ~E1000ENetworkAdapter() override;
|
||||
|
||||
virtual const char* purpose() const override { return class_name(); }
|
||||
|
||||
private:
|
||||
E1000ENetworkAdapter(PCI::Address, u8 irq);
|
||||
|
||||
virtual const char* class_name() const override { return "E1000ENetworkAdapter"; }
|
||||
|
||||
virtual void detect_eeprom() override;
|
||||
virtual u32 read_eeprom(u8 address) override;
|
||||
};
|
||||
}
|
|
@ -164,23 +164,39 @@ UNMAP_AFTER_INIT RefPtr<E1000NetworkAdapter> E1000NetworkAdapter::try_to_initial
|
|||
if (!is_valid_device_id(id.device_id))
|
||||
return {};
|
||||
u8 irq = PCI::get_interrupt_line(address);
|
||||
return adopt_ref_if_nonnull(new E1000NetworkAdapter(address, irq));
|
||||
auto adapter = adopt_ref_if_nonnull(new E1000NetworkAdapter(address, irq));
|
||||
if (!adapter)
|
||||
return {};
|
||||
if (adapter->initialize())
|
||||
return adapter;
|
||||
return {};
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT E1000NetworkAdapter::E1000NetworkAdapter(PCI::Address address, u8 irq)
|
||||
: PCI::Device(address, irq)
|
||||
, m_io_base(PCI::get_BAR1(pci_address()) & ~1)
|
||||
, m_rx_descriptors_region(MM.allocate_contiguous_kernel_region(page_round_up(sizeof(e1000_rx_desc) * number_of_rx_descriptors + 16), "E1000 RX", Region::Access::Read | Region::Access::Write))
|
||||
, m_tx_descriptors_region(MM.allocate_contiguous_kernel_region(page_round_up(sizeof(e1000_tx_desc) * number_of_tx_descriptors + 16), "E1000 TX", Region::Access::Read | Region::Access::Write))
|
||||
UNMAP_AFTER_INIT void E1000NetworkAdapter::setup_link()
|
||||
{
|
||||
set_interface_name(address);
|
||||
u32 flags = in32(REG_CTRL);
|
||||
out32(REG_CTRL, flags | ECTRL_SLU);
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT void E1000NetworkAdapter::setup_interrupts()
|
||||
{
|
||||
out32(REG_INTERRUPT_RATE, 6000); // Interrupt rate of 1.536 milliseconds
|
||||
out32(REG_INTERRUPT_MASK_SET, INTERRUPT_LSC | INTERRUPT_RXT0 | INTERRUPT_RXO);
|
||||
in32(REG_INTERRUPT_CAUSE_READ);
|
||||
enable_irq();
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT bool E1000NetworkAdapter::initialize()
|
||||
{
|
||||
dmesgln("E1000: Found @ {}", pci_address());
|
||||
|
||||
enable_bus_mastering(pci_address());
|
||||
|
||||
m_io_base = IOAddress(PCI::get_BAR1(pci_address()) & ~1);
|
||||
|
||||
size_t mmio_base_size = PCI::get_BAR_space_size(pci_address(), 0);
|
||||
m_mmio_region = MM.allocate_kernel_region(PhysicalAddress(page_base_of(PCI::get_BAR0(pci_address()))), page_round_up(mmio_base_size), "E1000 MMIO", Region::Access::Read | Region::Access::Write, Region::Cacheable::No);
|
||||
if (!m_mmio_region)
|
||||
return false;
|
||||
m_mmio_base = m_mmio_region->vaddr();
|
||||
m_use_mmio = true;
|
||||
m_interrupt_line = PCI::get_interrupt_line(pci_address());
|
||||
|
@ -194,18 +210,20 @@ UNMAP_AFTER_INIT E1000NetworkAdapter::E1000NetworkAdapter(PCI::Address address,
|
|||
const auto& mac = mac_address();
|
||||
dmesgln("E1000: MAC address: {}", mac.to_string());
|
||||
|
||||
u32 flags = in32(REG_CTRL);
|
||||
out32(REG_CTRL, flags | ECTRL_SLU);
|
||||
|
||||
out32(REG_INTERRUPT_RATE, 6000); // Interrupt rate of 1.536 milliseconds
|
||||
|
||||
initialize_rx_descriptors();
|
||||
initialize_tx_descriptors();
|
||||
|
||||
out32(REG_INTERRUPT_MASK_SET, INTERRUPT_LSC | INTERRUPT_RXT0 | INTERRUPT_RXO);
|
||||
in32(REG_INTERRUPT_CAUSE_READ);
|
||||
setup_link();
|
||||
setup_interrupts();
|
||||
return true;
|
||||
}
|
||||
|
||||
enable_irq();
|
||||
UNMAP_AFTER_INIT E1000NetworkAdapter::E1000NetworkAdapter(PCI::Address address, u8 irq)
|
||||
: PCI::Device(address, irq)
|
||||
, m_rx_descriptors_region(MM.allocate_contiguous_kernel_region(page_round_up(sizeof(e1000_rx_desc) * number_of_rx_descriptors + 16), "E1000 RX", Region::Access::Read | Region::Access::Write))
|
||||
, m_tx_descriptors_region(MM.allocate_contiguous_kernel_region(page_round_up(sizeof(e1000_tx_desc) * number_of_tx_descriptors + 16), "E1000 TX", Region::Access::Read | Region::Access::Write))
|
||||
{
|
||||
set_interface_name(pci_address());
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT E1000NetworkAdapter::~E1000NetworkAdapter()
|
||||
|
|
|
@ -17,11 +17,13 @@
|
|||
|
||||
namespace Kernel {
|
||||
|
||||
class E1000NetworkAdapter final : public NetworkAdapter
|
||||
class E1000NetworkAdapter : public NetworkAdapter
|
||||
, public PCI::Device {
|
||||
public:
|
||||
static RefPtr<E1000NetworkAdapter> try_to_initialize(PCI::Address);
|
||||
|
||||
virtual bool initialize();
|
||||
|
||||
virtual ~E1000NetworkAdapter() override;
|
||||
|
||||
virtual void send_raw(ReadonlyBytes) override;
|
||||
|
@ -29,7 +31,10 @@ public:
|
|||
|
||||
virtual const char* purpose() const override { return class_name(); }
|
||||
|
||||
private:
|
||||
protected:
|
||||
void setup_interrupts();
|
||||
void setup_link();
|
||||
|
||||
E1000NetworkAdapter(PCI::Address, u8 irq);
|
||||
virtual void handle_irq(const RegisterState&) override;
|
||||
virtual const char* class_name() const override { return "E1000NetworkAdapter"; }
|
||||
|
@ -53,8 +58,8 @@ private:
|
|||
volatile uint16_t special { 0 };
|
||||
};
|
||||
|
||||
void detect_eeprom();
|
||||
u32 read_eeprom(u8 address);
|
||||
virtual void detect_eeprom();
|
||||
virtual u32 read_eeprom(u8 address);
|
||||
void read_mac_address();
|
||||
|
||||
void write_command(u16 address, u32);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <Kernel/Debug.h>
|
||||
#include <Kernel/IO.h>
|
||||
#include <Kernel/Multiboot.h>
|
||||
#include <Kernel/Net/E1000ENetworkAdapter.h>
|
||||
#include <Kernel/Net/E1000NetworkAdapter.h>
|
||||
#include <Kernel/Net/LoopbackAdapter.h>
|
||||
#include <Kernel/Net/NE2000NetworkAdapter.h>
|
||||
|
@ -76,6 +77,8 @@ UNMAP_AFTER_INIT RefPtr<NetworkAdapter> NetworkingManagement::determine_network_
|
|||
{
|
||||
if (auto candidate = E1000NetworkAdapter::try_to_initialize(address); !candidate.is_null())
|
||||
return candidate;
|
||||
if (auto candidate = E1000ENetworkAdapter::try_to_initialize(address); !candidate.is_null())
|
||||
return candidate;
|
||||
if (auto candidate = RTL8139NetworkAdapter::try_to_initialize(address); !candidate.is_null())
|
||||
return candidate;
|
||||
if (auto candidate = NE2000NetworkAdapter::try_to_initialize(address); !candidate.is_null())
|
||||
|
|
|
@ -35,6 +35,7 @@ set(DOUBLECLICK_DEBUG ON)
|
|||
set(DWARF_DEBUG ON)
|
||||
set(DYNAMIC_LOAD_DEBUG ON)
|
||||
set(E1000_DEBUG ON)
|
||||
set(E1000E_DEBUG ON)
|
||||
set(EDITOR_DEBUG ON)
|
||||
set(ELF_IMAGE_DEBUG ON)
|
||||
set(EMOJI_DEBUG ON)
|
||||
|
|
Loading…
Reference in a new issue