Serenity Operating System
at master 271 lines 9.8 kB view raw
1/* 2 * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/MACAddress.h> 8#include <Kernel/Bus/PCI/API.h> 9#include <Kernel/Bus/PCI/IDs.h> 10#include <Kernel/Net/Intel/E1000ENetworkAdapter.h> 11#include <Kernel/Net/NetworkingManagement.h> 12#include <Kernel/Sections.h> 13 14namespace Kernel { 15 16#define REG_EEPROM 0x0014 17 18static bool is_valid_device_id(u16 device_id) 19{ 20 // Note: All ids listed here are valid, but only the ones that are verified working are set to 'true' 21 switch (device_id) { 22 case 0x10D3: // 82574L 23 return true; 24 case 0x1000: // 82542 25 case 0x0438: // DH89XXCC_SGMII 26 case 0x043A: // DH89XXCC_SERDES 27 case 0x043C: // DH89XXCC_BACKPLANE 28 case 0x0440: // DH89XXCC_SFP 29 case 0x1001: // 82543GC_FIBER 30 case 0x1004: // 82543GC_COPPER 31 case 0x1008: // 82544EI_COPPER 32 case 0x1009: // 82544EI_FIBER 33 case 0x100C: // 82544GC_COPPER 34 case 0x100D: // 82544GC_LOM 35 case 0x100E: // 82540EM 36 case 0x100F: // 82545EM_COPPER 37 case 0x1010: // 82546EB_COPPER 38 case 0x1011: // 82545EM_FIBER 39 case 0x1012: // 82546EB_FIBER 40 case 0x1013: // 82541EI 41 case 0x1014: // 82541ER_LOM 42 case 0x1015: // 82540EM_LOM 43 case 0x1016: // 82540EP_LOM 44 case 0x1017: // 82540EP 45 case 0x1018: // 82541EI_MOBILE 46 case 0x1019: // 82547EI 47 case 0x101A: // 82547EI_MOBILE 48 case 0x101D: // 82546EB_QUAD_COPPER 49 case 0x101E: // 82540EP_LP 50 case 0x1026: // 82545GM_COPPER 51 case 0x1027: // 82545GM_FIBER 52 case 0x1028: // 82545GM_SERDES 53 case 0x1049: // ICH8_IGP_M_AMT 54 case 0x104A: // ICH8_IGP_AMT 55 case 0x104B: // ICH8_IGP_C 56 case 0x104C: // ICH8_IFE 57 case 0x104D: // ICH8_IGP_M 58 case 0x105E: // 82571EB_COPPER 59 case 0x105F: // 82571EB_FIBER 60 case 0x1060: // 82571EB_SERDES 61 case 0x1075: // 82547GI 62 case 0x1076: // 82541GI 63 case 0x1077: // 82541GI_MOBILE 64 case 0x1078: // 82541ER 65 case 0x1079: // 82546GB_COPPER 66 case 0x107A: // 82546GB_FIBER 67 case 0x107B: // 82546GB_SERDES 68 case 0x107C: // 82541GI_LF 69 case 0x107D: // 82572EI_COPPER 70 case 0x107E: // 82572EI_FIBER 71 case 0x107F: // 82572EI_SERDES 72 case 0x108A: // 82546GB_PCIE 73 case 0x108B: // 82573E 74 case 0x108C: // 82573E_IAMT 75 case 0x1096: // 80003ES2LAN_COPPER_DPT 76 case 0x1098: // 80003ES2LAN_SERDES_DPT 77 case 0x1099: // 82546GB_QUAD_COPPER 78 case 0x109A: // 82573L 79 case 0x10A4: // 82571EB_QUAD_COPPER 80 case 0x10A5: // 82571EB_QUAD_FIBER 81 case 0x10A7: // 82575EB_COPPER 82 case 0x10A9: // 82575EB_FIBER_SERDES 83 case 0x10B5: // 82546GB_QUAD_COPPER_KSP3 84 case 0x10B9: // 82572EI 85 case 0x10BA: // 80003ES2LAN_COPPER_SPT 86 case 0x10BB: // 80003ES2LAN_SERDES_SPT 87 case 0x10BC: // 82571EB_QUAD_COPPER_LP 88 case 0x10BD: // ICH9_IGP_AMT 89 case 0x10BF: // ICH9_IGP_M 90 case 0x10C0: // ICH9_IFE 91 case 0x10C2: // ICH9_IFE_G 92 case 0x10C3: // ICH9_IFE_GT 93 case 0x10C4: // ICH8_IFE_GT 94 case 0x10C5: // ICH8_IFE_G 95 case 0x10C9: // 82576 96 case 0x10CA: // 82576_VF 97 case 0x10CB: // ICH9_IGP_M_V 98 case 0x10CC: // ICH10_R_BM_LM 99 case 0x10CD: // ICH10_R_BM_LF 100 case 0x10CE: // ICH10_R_BM_V 101 case 0x10D5: // 82571PT_QUAD_COPPER 102 case 0x10D6: // 82575GB_QUAD_COPPER 103 case 0x10D9: // 82571EB_SERDES_DUAL 104 case 0x10DA: // 82571EB_SERDES_QUAD 105 case 0x10DE: // ICH10_D_BM_LM 106 case 0x10DF: // ICH10_D_BM_LF 107 case 0x10E5: // ICH9_BM 108 case 0x10E6: // 82576_FIBER 109 case 0x10E7: // 82576_SERDES 110 case 0x10E8: // 82576_QUAD_COPPER 111 case 0x10EA: // PCH_M_HV_LM 112 case 0x10EB: // PCH_M_HV_LC 113 case 0x10EF: // PCH_D_HV_DM 114 case 0x10F0: // PCH_D_HV_DC 115 case 0x10F5: // ICH9_IGP_M_AMT 116 case 0x10F6: // 82574LA 117 case 0x1501: // ICH8_82567V_3 118 case 0x1502: // PCH2_LV_LM 119 case 0x1503: // PCH2_LV_V 120 case 0x150A: // 82576_NS 121 case 0x150C: // 82583V 122 case 0x150D: // 82576_SERDES_QUAD 123 case 0x150E: // 82580_COPPER 124 case 0x150F: // 82580_FIBER 125 case 0x1510: // 82580_SERDES 126 case 0x1511: // 82580_SGMII 127 case 0x1516: // 82580_COPPER_DUAL 128 case 0x1518: // 82576_NS_SERDES 129 case 0x1520: // I350_VF 130 case 0x1521: // I350_COPPER 131 case 0x1522: // I350_FIBER 132 case 0x1523: // I350_SERDES 133 case 0x1524: // I350_SGMII 134 case 0x1525: // ICH10_D_BM_V 135 case 0x1526: // 82576_QUAD_COPPER_ET2 136 case 0x1527: // 82580_QUAD_FIBER 137 case 0x152D: // 82576_VF_HV 138 case 0x152F: // I350_VF_HV 139 case 0x1533: // I210_COPPER 140 case 0x1534: // I210_COPPER_OEM1 141 case 0x1535: // I210_COPPER_IT 142 case 0x1536: // I210_FIBER 143 case 0x1537: // I210_SERDES 144 case 0x1538: // I210_SGMII 145 case 0x1539: // I211_COPPER 146 case 0x153A: // PCH_LPT_I217_LM 147 case 0x153B: // PCH_LPT_I217_V 148 case 0x1546: // I350_DA4 149 case 0x1559: // PCH_LPTLP_I218_V 150 case 0x155A: // PCH_LPTLP_I218_LM 151 case 0x156F: // PCH_SPT_I219_LM 152 case 0x1570: // PCH_SPT_I219_V 153 case 0x157B: // I210_COPPER_FLASHLESS 154 case 0x157C: // I210_SERDES_FLASHLESS 155 case 0x15A0: // PCH_I218_LM2 156 case 0x15A1: // PCH_I218_V2 157 case 0x15A2: // PCH_I218_LM3 158 case 0x15A3: // PCH_I218_V3 159 case 0x15B7: // PCH_SPT_I219_LM2 160 case 0x15B8: // PCH_SPT_I219_V2 161 case 0x15B9: // PCH_LBG_I219_LM3 162 case 0x15BB: // PCH_CNP_I219_LM7 163 case 0x15BC: // PCH_CNP_I219_V7 164 case 0x15BD: // PCH_CNP_I219_LM6 165 case 0x15BE: // PCH_CNP_I219_V6 166 case 0x15D6: // PCH_SPT_I219_V5 167 case 0x15D7: // PCH_SPT_I219_LM4 168 case 0x15D8: // PCH_SPT_I219_V4 169 case 0x15DF: // PCH_ICP_I219_LM8 170 case 0x15E0: // PCH_ICP_I219_V8 171 case 0x15E1: // PCH_ICP_I219_LM9 172 case 0x15E2: // PCH_ICP_I219_V9 173 case 0x15E3: // PCH_SPT_I219_LM5 174 case 0x1F40: // I354_BACKPLANE_1GBPS 175 case 0x1F41: // I354_SGMII 176 case 0x1F45: // I354_BACKPLANE_2_5GBPS 177 case 0x294C: // ICH9_IGP_C 178 return false; 179 default: 180 return false; 181 } 182} 183 184UNMAP_AFTER_INIT ErrorOr<bool> E1000ENetworkAdapter::probe(PCI::DeviceIdentifier const& pci_device_identifier) 185{ 186 if (pci_device_identifier.hardware_id().vendor_id != PCI::VendorID::Intel) 187 return false; 188 return is_valid_device_id(pci_device_identifier.hardware_id().device_id); 189} 190 191UNMAP_AFTER_INIT ErrorOr<NonnullLockRefPtr<NetworkAdapter>> E1000ENetworkAdapter::create(PCI::DeviceIdentifier const& pci_device_identifier) 192{ 193 u8 irq = pci_device_identifier.interrupt_line().value(); 194 auto interface_name = TRY(NetworkingManagement::generate_interface_name_from_pci_address(pci_device_identifier)); 195 auto registers_io_window = TRY(IOWindow::create_for_pci_device_bar(pci_device_identifier, PCI::HeaderType0BaseRegister::BAR0)); 196 197 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)); 198 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(); 199 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)); 200 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)); 201 202 return TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) E1000ENetworkAdapter(pci_device_identifier, 203 irq, move(registers_io_window), 204 move(rx_buffer_region), 205 move(tx_buffer_region), 206 move(rx_descriptors_region), 207 move(tx_descriptors_region), 208 move(interface_name)))); 209} 210 211UNMAP_AFTER_INIT ErrorOr<void> E1000ENetworkAdapter::initialize(Badge<NetworkingManagement>) 212{ 213 dmesgln("E1000e: Found @ {}", device_identifier().address()); 214 enable_bus_mastering(device_identifier()); 215 216 dmesgln("E1000e: IO base: {}", m_registers_io_window); 217 dmesgln("E1000e: Interrupt line: {}", interrupt_number()); 218 detect_eeprom(); 219 dmesgln("E1000e: Has EEPROM? {}", m_has_eeprom); 220 read_mac_address(); 221 auto const& mac = mac_address(); 222 dmesgln("E1000e: MAC address: {}", mac.to_string()); 223 224 initialize_rx_descriptors(); 225 initialize_tx_descriptors(); 226 227 setup_link(); 228 setup_interrupts(); 229 return {}; 230} 231 232UNMAP_AFTER_INIT E1000ENetworkAdapter::E1000ENetworkAdapter(PCI::DeviceIdentifier const& device_identifier, u8 irq, 233 NonnullOwnPtr<IOWindow> registers_io_window, NonnullOwnPtr<Memory::Region> rx_buffer_region, 234 NonnullOwnPtr<Memory::Region> tx_buffer_region, NonnullOwnPtr<Memory::Region> rx_descriptors_region, 235 NonnullOwnPtr<Memory::Region> tx_descriptors_region, NonnullOwnPtr<KString> interface_name) 236 : E1000NetworkAdapter(device_identifier, irq, move(registers_io_window), 237 move(rx_buffer_region), 238 move(tx_buffer_region), 239 move(rx_descriptors_region), 240 move(tx_descriptors_region), 241 move(interface_name)) 242{ 243} 244 245UNMAP_AFTER_INIT E1000ENetworkAdapter::~E1000ENetworkAdapter() = default; 246 247UNMAP_AFTER_INIT void E1000ENetworkAdapter::detect_eeprom() 248{ 249 // FIXME: Try to find a way to detect if EEPROM exists instead of assuming it is 250 m_has_eeprom = true; 251} 252 253UNMAP_AFTER_INIT u32 E1000ENetworkAdapter::read_eeprom(u8 address) 254{ 255 VERIFY(m_has_eeprom); 256 u16 data = 0; 257 u32 tmp = 0; 258 if (m_has_eeprom) { 259 out32(REG_EEPROM, ((u32)address << 2) | 1); 260 while (!((tmp = in32(REG_EEPROM)) & (1 << 1))) 261 ; 262 } else { 263 out32(REG_EEPROM, ((u32)address << 2) | 1); 264 while (!((tmp = in32(REG_EEPROM)) & (1 << 1))) 265 ; 266 } 267 data = (tmp >> 16) & 0xffff; 268 return data; 269} 270 271}