mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 11:58:12 +00:00

Instead of using a clunky if-statement paradigm, we now have all drivers being declaring two methods for their adapter class - create and probe. These methods are linked in each PCINetworkDriverInitializer structure, in a new s_initializers static list of them. Then, when we probe for a PCI device, we use each probe method and if there's a match, then the corresponding create method is called. After the adapter instance is created, we call the virtual initialize method on it, because many drivers actually require a sort of post-construction initialization sequence to ensure the network adapter can properly function. As a result of this change, it's much more easy to add more drivers and the initialization code is more readable and it's easier to understand when and where things could fail in the whole initialization sequence.
271 lines
9.5 KiB
C++
271 lines
9.5 KiB
C++
/*
|
|
* Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <AK/MACAddress.h>
|
|
#include <Kernel/Bus/PCI/API.h>
|
|
#include <Kernel/Bus/PCI/IDs.h>
|
|
#include <Kernel/Net/Intel/E1000ENetworkAdapter.h>
|
|
#include <Kernel/Net/NetworkingManagement.h>
|
|
#include <Kernel/Sections.h>
|
|
|
|
namespace Kernel {
|
|
|
|
#define REG_EEPROM 0x0014
|
|
|
|
static bool is_valid_device_id(u16 device_id)
|
|
{
|
|
// Note: All ids listed here are valid, but only the ones that are verified working are set to 'true'
|
|
switch (device_id) {
|
|
case 0x10D3: // 82574L
|
|
return true;
|
|
case 0x1000: // 82542
|
|
case 0x0438: // DH89XXCC_SGMII
|
|
case 0x043A: // DH89XXCC_SERDES
|
|
case 0x043C: // DH89XXCC_BACKPLANE
|
|
case 0x0440: // DH89XXCC_SFP
|
|
case 0x1001: // 82543GC_FIBER
|
|
case 0x1004: // 82543GC_COPPER
|
|
case 0x1008: // 82544EI_COPPER
|
|
case 0x1009: // 82544EI_FIBER
|
|
case 0x100C: // 82544GC_COPPER
|
|
case 0x100D: // 82544GC_LOM
|
|
case 0x100E: // 82540EM
|
|
case 0x100F: // 82545EM_COPPER
|
|
case 0x1010: // 82546EB_COPPER
|
|
case 0x1011: // 82545EM_FIBER
|
|
case 0x1012: // 82546EB_FIBER
|
|
case 0x1013: // 82541EI
|
|
case 0x1014: // 82541ER_LOM
|
|
case 0x1015: // 82540EM_LOM
|
|
case 0x1016: // 82540EP_LOM
|
|
case 0x1017: // 82540EP
|
|
case 0x1018: // 82541EI_MOBILE
|
|
case 0x1019: // 82547EI
|
|
case 0x101A: // 82547EI_MOBILE
|
|
case 0x101D: // 82546EB_QUAD_COPPER
|
|
case 0x101E: // 82540EP_LP
|
|
case 0x1026: // 82545GM_COPPER
|
|
case 0x1027: // 82545GM_FIBER
|
|
case 0x1028: // 82545GM_SERDES
|
|
case 0x1049: // ICH8_IGP_M_AMT
|
|
case 0x104A: // ICH8_IGP_AMT
|
|
case 0x104B: // ICH8_IGP_C
|
|
case 0x104C: // ICH8_IFE
|
|
case 0x104D: // ICH8_IGP_M
|
|
case 0x105E: // 82571EB_COPPER
|
|
case 0x105F: // 82571EB_FIBER
|
|
case 0x1060: // 82571EB_SERDES
|
|
case 0x1075: // 82547GI
|
|
case 0x1076: // 82541GI
|
|
case 0x1077: // 82541GI_MOBILE
|
|
case 0x1078: // 82541ER
|
|
case 0x1079: // 82546GB_COPPER
|
|
case 0x107A: // 82546GB_FIBER
|
|
case 0x107B: // 82546GB_SERDES
|
|
case 0x107C: // 82541GI_LF
|
|
case 0x107D: // 82572EI_COPPER
|
|
case 0x107E: // 82572EI_FIBER
|
|
case 0x107F: // 82572EI_SERDES
|
|
case 0x108A: // 82546GB_PCIE
|
|
case 0x108B: // 82573E
|
|
case 0x108C: // 82573E_IAMT
|
|
case 0x1096: // 80003ES2LAN_COPPER_DPT
|
|
case 0x1098: // 80003ES2LAN_SERDES_DPT
|
|
case 0x1099: // 82546GB_QUAD_COPPER
|
|
case 0x109A: // 82573L
|
|
case 0x10A4: // 82571EB_QUAD_COPPER
|
|
case 0x10A5: // 82571EB_QUAD_FIBER
|
|
case 0x10A7: // 82575EB_COPPER
|
|
case 0x10A9: // 82575EB_FIBER_SERDES
|
|
case 0x10B5: // 82546GB_QUAD_COPPER_KSP3
|
|
case 0x10B9: // 82572EI
|
|
case 0x10BA: // 80003ES2LAN_COPPER_SPT
|
|
case 0x10BB: // 80003ES2LAN_SERDES_SPT
|
|
case 0x10BC: // 82571EB_QUAD_COPPER_LP
|
|
case 0x10BD: // ICH9_IGP_AMT
|
|
case 0x10BF: // ICH9_IGP_M
|
|
case 0x10C0: // ICH9_IFE
|
|
case 0x10C2: // ICH9_IFE_G
|
|
case 0x10C3: // ICH9_IFE_GT
|
|
case 0x10C4: // ICH8_IFE_GT
|
|
case 0x10C5: // ICH8_IFE_G
|
|
case 0x10C9: // 82576
|
|
case 0x10CA: // 82576_VF
|
|
case 0x10CB: // ICH9_IGP_M_V
|
|
case 0x10CC: // ICH10_R_BM_LM
|
|
case 0x10CD: // ICH10_R_BM_LF
|
|
case 0x10CE: // ICH10_R_BM_V
|
|
case 0x10D5: // 82571PT_QUAD_COPPER
|
|
case 0x10D6: // 82575GB_QUAD_COPPER
|
|
case 0x10D9: // 82571EB_SERDES_DUAL
|
|
case 0x10DA: // 82571EB_SERDES_QUAD
|
|
case 0x10DE: // ICH10_D_BM_LM
|
|
case 0x10DF: // ICH10_D_BM_LF
|
|
case 0x10E5: // ICH9_BM
|
|
case 0x10E6: // 82576_FIBER
|
|
case 0x10E7: // 82576_SERDES
|
|
case 0x10E8: // 82576_QUAD_COPPER
|
|
case 0x10EA: // PCH_M_HV_LM
|
|
case 0x10EB: // PCH_M_HV_LC
|
|
case 0x10EF: // PCH_D_HV_DM
|
|
case 0x10F0: // PCH_D_HV_DC
|
|
case 0x10F5: // ICH9_IGP_M_AMT
|
|
case 0x10F6: // 82574LA
|
|
case 0x1501: // ICH8_82567V_3
|
|
case 0x1502: // PCH2_LV_LM
|
|
case 0x1503: // PCH2_LV_V
|
|
case 0x150A: // 82576_NS
|
|
case 0x150C: // 82583V
|
|
case 0x150D: // 82576_SERDES_QUAD
|
|
case 0x150E: // 82580_COPPER
|
|
case 0x150F: // 82580_FIBER
|
|
case 0x1510: // 82580_SERDES
|
|
case 0x1511: // 82580_SGMII
|
|
case 0x1516: // 82580_COPPER_DUAL
|
|
case 0x1518: // 82576_NS_SERDES
|
|
case 0x1520: // I350_VF
|
|
case 0x1521: // I350_COPPER
|
|
case 0x1522: // I350_FIBER
|
|
case 0x1523: // I350_SERDES
|
|
case 0x1524: // I350_SGMII
|
|
case 0x1525: // ICH10_D_BM_V
|
|
case 0x1526: // 82576_QUAD_COPPER_ET2
|
|
case 0x1527: // 82580_QUAD_FIBER
|
|
case 0x152D: // 82576_VF_HV
|
|
case 0x152F: // I350_VF_HV
|
|
case 0x1533: // I210_COPPER
|
|
case 0x1534: // I210_COPPER_OEM1
|
|
case 0x1535: // I210_COPPER_IT
|
|
case 0x1536: // I210_FIBER
|
|
case 0x1537: // I210_SERDES
|
|
case 0x1538: // I210_SGMII
|
|
case 0x1539: // I211_COPPER
|
|
case 0x153A: // PCH_LPT_I217_LM
|
|
case 0x153B: // PCH_LPT_I217_V
|
|
case 0x1546: // I350_DA4
|
|
case 0x1559: // PCH_LPTLP_I218_V
|
|
case 0x155A: // PCH_LPTLP_I218_LM
|
|
case 0x156F: // PCH_SPT_I219_LM
|
|
case 0x1570: // PCH_SPT_I219_V
|
|
case 0x157B: // I210_COPPER_FLASHLESS
|
|
case 0x157C: // I210_SERDES_FLASHLESS
|
|
case 0x15A0: // PCH_I218_LM2
|
|
case 0x15A1: // PCH_I218_V2
|
|
case 0x15A2: // PCH_I218_LM3
|
|
case 0x15A3: // PCH_I218_V3
|
|
case 0x15B7: // PCH_SPT_I219_LM2
|
|
case 0x15B8: // PCH_SPT_I219_V2
|
|
case 0x15B9: // PCH_LBG_I219_LM3
|
|
case 0x15BB: // PCH_CNP_I219_LM7
|
|
case 0x15BC: // PCH_CNP_I219_V7
|
|
case 0x15BD: // PCH_CNP_I219_LM6
|
|
case 0x15BE: // PCH_CNP_I219_V6
|
|
case 0x15D6: // PCH_SPT_I219_V5
|
|
case 0x15D7: // PCH_SPT_I219_LM4
|
|
case 0x15D8: // PCH_SPT_I219_V4
|
|
case 0x15DF: // PCH_ICP_I219_LM8
|
|
case 0x15E0: // PCH_ICP_I219_V8
|
|
case 0x15E1: // PCH_ICP_I219_LM9
|
|
case 0x15E2: // PCH_ICP_I219_V9
|
|
case 0x15E3: // PCH_SPT_I219_LM5
|
|
case 0x1F40: // I354_BACKPLANE_1GBPS
|
|
case 0x1F41: // I354_SGMII
|
|
case 0x1F45: // I354_BACKPLANE_2_5GBPS
|
|
case 0x294C: // ICH9_IGP_C
|
|
return false;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
UNMAP_AFTER_INIT ErrorOr<bool> E1000ENetworkAdapter::probe(PCI::DeviceIdentifier const& pci_device_identifier)
|
|
{
|
|
if (pci_device_identifier.hardware_id().vendor_id != PCI::VendorID::Intel)
|
|
return false;
|
|
return is_valid_device_id(pci_device_identifier.hardware_id().device_id);
|
|
}
|
|
|
|
UNMAP_AFTER_INIT ErrorOr<NonnullLockRefPtr<NetworkAdapter>> E1000ENetworkAdapter::create(PCI::DeviceIdentifier const& pci_device_identifier)
|
|
{
|
|
u8 irq = pci_device_identifier.interrupt_line().value();
|
|
auto interface_name = TRY(NetworkingManagement::generate_interface_name_from_pci_address(pci_device_identifier));
|
|
auto registers_io_window = TRY(IOWindow::create_for_pci_device_bar(pci_device_identifier, PCI::HeaderType0BaseRegister::BAR0));
|
|
|
|
auto rx_buffer_region = TRY(MM.allocate_contiguous_kernel_region(rx_buffer_size * number_of_rx_descriptors, "E1000 RX buffers"sv, Memory::Region::Access::ReadWrite));
|
|
auto tx_buffer_region = MM.allocate_contiguous_kernel_region(tx_buffer_size * number_of_tx_descriptors, "E1000 TX buffers"sv, Memory::Region::Access::ReadWrite).release_value();
|
|
auto rx_descriptors_region = TRY(MM.allocate_contiguous_kernel_region(TRY(Memory::page_round_up(sizeof(e1000_rx_desc) * number_of_rx_descriptors)), "E1000 RX Descriptors"sv, Memory::Region::Access::ReadWrite));
|
|
auto tx_descriptors_region = TRY(MM.allocate_contiguous_kernel_region(TRY(Memory::page_round_up(sizeof(e1000_tx_desc) * number_of_tx_descriptors)), "E1000 TX Descriptors"sv, Memory::Region::Access::ReadWrite));
|
|
|
|
return TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) E1000ENetworkAdapter(pci_device_identifier.address(),
|
|
irq, move(registers_io_window),
|
|
move(rx_buffer_region),
|
|
move(tx_buffer_region),
|
|
move(rx_descriptors_region),
|
|
move(tx_descriptors_region),
|
|
move(interface_name))));
|
|
}
|
|
|
|
UNMAP_AFTER_INIT ErrorOr<void> E1000ENetworkAdapter::initialize(Badge<NetworkingManagement>)
|
|
{
|
|
dmesgln("E1000e: Found @ {}", pci_address());
|
|
enable_bus_mastering(pci_address());
|
|
|
|
dmesgln("E1000e: IO base: {}", m_registers_io_window);
|
|
dmesgln("E1000e: Interrupt line: {}", interrupt_number());
|
|
detect_eeprom();
|
|
dmesgln("E1000e: Has EEPROM? {}", m_has_eeprom);
|
|
read_mac_address();
|
|
auto const& mac = mac_address();
|
|
dmesgln("E1000e: MAC address: {}", mac.to_string());
|
|
|
|
initialize_rx_descriptors();
|
|
initialize_tx_descriptors();
|
|
|
|
setup_link();
|
|
setup_interrupts();
|
|
return {};
|
|
}
|
|
|
|
UNMAP_AFTER_INIT E1000ENetworkAdapter::E1000ENetworkAdapter(PCI::Address address, u8 irq,
|
|
NonnullOwnPtr<IOWindow> registers_io_window, NonnullOwnPtr<Memory::Region> rx_buffer_region,
|
|
NonnullOwnPtr<Memory::Region> tx_buffer_region, NonnullOwnPtr<Memory::Region> rx_descriptors_region,
|
|
NonnullOwnPtr<Memory::Region> tx_descriptors_region, NonnullOwnPtr<KString> interface_name)
|
|
: E1000NetworkAdapter(address, irq, move(registers_io_window),
|
|
move(rx_buffer_region),
|
|
move(tx_buffer_region),
|
|
move(rx_descriptors_region),
|
|
move(tx_descriptors_region),
|
|
move(interface_name))
|
|
{
|
|
}
|
|
|
|
UNMAP_AFTER_INIT E1000ENetworkAdapter::~E1000ENetworkAdapter() = default;
|
|
|
|
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;
|
|
}
|
|
|
|
}
|