mirror of
https://github.com/SerenityOS/serenity.git
synced 2026-11-07 12:38:38 -10:00
Kernel/Net: Use the new MDIO abstraction to initialize E1000E properly
This makes the virtual e1000e network adapter from QEMU work with serenity again. This was possibly broken by a QEMU update?
This commit is contained in:
1 parent
6fa1f85c74
commit
84d1758de3
2 files changed
+80
-2
No files matched your search
@@ -10,16 +10,35 @@
|
||||
#include <Kernel/Net/Intel/E1000ENetworkAdapter.h>
|
||||
#include <Kernel/Net/NetworkingManagement.h>
|
||||
#include <Kernel/Sections.h>
|
||||
#include <Kernel/Tasks/Process.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
#define REG_CTRL 0x0000
|
||||
#define REG_EECD 0x0010
|
||||
#define REG_EEPROM 0x0014
|
||||
#define REG_MDIC 0x0020
|
||||
|
||||
// CTRL Register
|
||||
|
||||
#define REG_CTRL_SLU (1 << 6)
|
||||
|
||||
// EECD Register
|
||||
|
||||
#define EECD_PRES 0x100
|
||||
|
||||
// MIDC Register
|
||||
|
||||
#define REG_MDIC_DATA_MASK (0xffff << 0)
|
||||
#define REG_MDIC_DATA_OFFSET 0
|
||||
#define REG_MDIC_REGADD_OFFSET 16
|
||||
#define REG_MDIC_R (1 << 28)
|
||||
#define REG_MDIC_OP_WRITE (0b01 << 26)
|
||||
#define REG_MDIC_OP_READ (0b10 << 26)
|
||||
#define REG_MDIC_PHYADD_OFFSET 21
|
||||
|
||||
#define GIGABIT_PHY_ID 1
|
||||
|
||||
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'
|
||||
@@ -226,6 +245,8 @@ UNMAP_AFTER_INIT ErrorOr<void> E1000ENetworkAdapter::initialize(Badge<Networking
|
||||
auto const& mac = mac_address();
|
||||
dmesgln("E1000e: MAC address: {}", mac.to_string());
|
||||
|
||||
m_mdio_handling_process = TRY(spawn_mdio_handling_task(GIGABIT_PHY_ID));
|
||||
|
||||
initialize_rx_descriptors();
|
||||
initialize_tx_descriptors();
|
||||
|
||||
@@ -248,7 +269,54 @@ UNMAP_AFTER_INIT E1000ENetworkAdapter::E1000ENetworkAdapter(StringView interface
|
||||
{
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT E1000ENetworkAdapter::~E1000ENetworkAdapter() = default;
|
||||
UNMAP_AFTER_INIT E1000ENetworkAdapter::~E1000ENetworkAdapter()
|
||||
{
|
||||
if (m_mdio_handling_process) {
|
||||
m_mdio_handling_process->die();
|
||||
// Block until all threads exited to prevent UAF
|
||||
ErrorOr<siginfo_t> result = siginfo_t {};
|
||||
(void)Thread::current()->block<Thread::WaitBlocker>({}, WEXITED, m_mdio_handling_process.release_nonnull(), result);
|
||||
}
|
||||
}
|
||||
|
||||
void E1000ENetworkAdapter::on_phy_link_status_change(MDIO::LinkStatus link_status)
|
||||
{
|
||||
auto ctrl = in32(REG_CTRL);
|
||||
|
||||
if (link_status == MDIO::LinkStatus::Up)
|
||||
ctrl |= REG_CTRL_SLU;
|
||||
else
|
||||
ctrl &= ~REG_CTRL_SLU;
|
||||
|
||||
out32(REG_CTRL, ctrl);
|
||||
}
|
||||
|
||||
u16 E1000ENetworkAdapter::read_phy_register(u8 phy_id, MDIO::Clause22::RegisterAddress address)
|
||||
{
|
||||
// FIXME: Newer controllers (like the I211) don't have a PHYADD field in the MDIC register.
|
||||
// They instead have it in a separate register.
|
||||
out32(REG_MDIC, REG_MDIC_OP_READ | (to_underlying(address) << REG_MDIC_REGADD_OFFSET) | (phy_id << REG_MDIC_PHYADD_OFFSET));
|
||||
|
||||
for (;;) {
|
||||
u32 mdic = in32(REG_MDIC);
|
||||
if ((mdic & REG_MDIC_R) == 0) {
|
||||
Processor::wait_check();
|
||||
continue;
|
||||
}
|
||||
|
||||
return (mdic & REG_MDIC_DATA_MASK) >> REG_MDIC_DATA_OFFSET;
|
||||
}
|
||||
}
|
||||
|
||||
void E1000ENetworkAdapter::write_phy_register(u8 phy_id, MDIO::Clause22::RegisterAddress address, u16 value)
|
||||
{
|
||||
// FIXME: Newer controllers (like the I211) don't have a PHYADD field in the MDIC register.
|
||||
// They instead have it in a separate register.
|
||||
out32(REG_MDIC, REG_MDIC_OP_WRITE | (to_underlying(address) << REG_MDIC_REGADD_OFFSET) | (value << REG_MDIC_DATA_OFFSET) | (phy_id << REG_MDIC_PHYADD_OFFSET));
|
||||
|
||||
while ((in32(REG_MDIC) & REG_MDIC_R) == 0)
|
||||
Processor::wait_check();
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT void E1000ENetworkAdapter::detect_eeprom()
|
||||
{
|
||||
|
||||
@@ -12,13 +12,15 @@
|
||||
#include <Kernel/Interrupts/IRQHandler.h>
|
||||
#include <Kernel/Library/IOWindow.h>
|
||||
#include <Kernel/Net/Intel/E1000NetworkAdapter.h>
|
||||
#include <Kernel/Net/MDIO.h>
|
||||
#include <Kernel/Net/NetworkAdapter.h>
|
||||
#include <Kernel/Security/Random.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class E1000ENetworkAdapter final
|
||||
: public E1000NetworkAdapter {
|
||||
: public E1000NetworkAdapter
|
||||
, public MDIO::Clause22::Interface {
|
||||
public:
|
||||
static ErrorOr<bool> probe(PCI::DeviceIdentifier const&);
|
||||
static ErrorOr<NonnullRefPtr<NetworkAdapter>> create(PCI::DeviceIdentifier const&);
|
||||
@@ -28,6 +30,12 @@ public:
|
||||
|
||||
virtual StringView purpose() const override { return class_name(); }
|
||||
|
||||
protected:
|
||||
// ^MDIO::Clause22::Interface
|
||||
virtual void on_phy_link_status_change(MDIO::LinkStatus) override;
|
||||
virtual u16 read_phy_register(u8 phy_id, MDIO::Clause22::RegisterAddress address) override;
|
||||
virtual void write_phy_register(u8 phy_id, MDIO::Clause22::RegisterAddress address, u16 value) override;
|
||||
|
||||
private:
|
||||
E1000ENetworkAdapter(StringView interface_name, PCI::DeviceIdentifier const&, InterruptNumber irq,
|
||||
NonnullOwnPtr<IOWindow> registers_io_window, NonnullOwnPtr<Memory::Region> rx_buffer_region,
|
||||
@@ -38,5 +46,7 @@ private:
|
||||
|
||||
virtual void detect_eeprom() override;
|
||||
virtual u32 read_eeprom(u8 address) override;
|
||||
|
||||
RefPtr<Process> m_mdio_handling_process;
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user