From 59fdeec7f5fc671286cc93b134f99dd4a6088aa4 Mon Sep 17 00:00:00 2001 From: Thomas Wagenveld Date: Sun, 25 Jul 2021 20:16:42 +0200 Subject: [PATCH] Kernel: Add interface to read link speed and duplex for NetworkAdapter Read the appropriate registers for RTL8139, RTL8168 and E1000. For NE2000 just assume 10mbit full duplex as there is no indicator for it in the pure NE2000 spec. Mock values for loopback. --- Kernel/Net/E1000NetworkAdapter.cpp | 25 +++++++++++++++++++++++++ Kernel/Net/E1000NetworkAdapter.h | 2 ++ Kernel/Net/LoopbackAdapter.h | 2 ++ Kernel/Net/NE2000NetworkAdapter.h | 6 ++++++ Kernel/Net/NetworkAdapter.h | 8 ++++++++ Kernel/Net/RTL8139NetworkAdapter.cpp | 23 +++++++++++++++++++++++ Kernel/Net/RTL8139NetworkAdapter.h | 2 ++ Kernel/Net/RTL8168NetworkAdapter.cpp | 28 ++++++++++++++++++++++++++++ Kernel/Net/RTL8168NetworkAdapter.h | 2 ++ 9 files changed, 98 insertions(+) diff --git a/Kernel/Net/E1000NetworkAdapter.cpp b/Kernel/Net/E1000NetworkAdapter.cpp index b0f8ec0178..568715ecce 100644 --- a/Kernel/Net/E1000NetworkAdapter.cpp +++ b/Kernel/Net/E1000NetworkAdapter.cpp @@ -466,4 +466,29 @@ void E1000NetworkAdapter::receive() } } +i32 E1000NetworkAdapter::link_speed() +{ + if (!link_up()) + return NetworkAdapter::LINKSPEED_INVALID; + + u32 speed = in32(REG_STATUS) & STATUS_SPEED; + switch (speed) { + case STATUS_SPEED_10MB: + return 10; + case STATUS_SPEED_100MB: + return 100; + case STATUS_SPEED_1000MB1: + case STATUS_SPEED_1000MB2: + return 1000; + default: + return NetworkAdapter::LINKSPEED_INVALID; + } +} + +bool E1000NetworkAdapter::link_full_duplex() +{ + u32 status = in32(REG_STATUS); + return !!(status & STATUS_FD); +} + } diff --git a/Kernel/Net/E1000NetworkAdapter.h b/Kernel/Net/E1000NetworkAdapter.h index 157b929ffa..2475d4d144 100644 --- a/Kernel/Net/E1000NetworkAdapter.h +++ b/Kernel/Net/E1000NetworkAdapter.h @@ -27,6 +27,8 @@ public: virtual void send_raw(ReadonlyBytes) override; virtual bool link_up() override; + virtual i32 link_speed() override; + virtual bool link_full_duplex() override; virtual StringView purpose() const override { return class_name(); } diff --git a/Kernel/Net/LoopbackAdapter.h b/Kernel/Net/LoopbackAdapter.h index a30538c73e..fb75abb3c0 100644 --- a/Kernel/Net/LoopbackAdapter.h +++ b/Kernel/Net/LoopbackAdapter.h @@ -23,6 +23,8 @@ public: virtual void send_raw(ReadonlyBytes) override; virtual StringView class_name() const override { return "LoopbackAdapter"; } virtual bool link_up() override { return true; } + virtual bool link_full_duplex() override { return true; } + virtual int link_speed() override { return 1000; } }; } diff --git a/Kernel/Net/NE2000NetworkAdapter.h b/Kernel/Net/NE2000NetworkAdapter.h index 2fda43ccfc..01f7f53b09 100644 --- a/Kernel/Net/NE2000NetworkAdapter.h +++ b/Kernel/Net/NE2000NetworkAdapter.h @@ -29,6 +29,12 @@ public: // just assume that it's up. return true; } + virtual i32 link_speed() + { + // Can only do 10mbit.. + return 10; + } + virtual bool link_full_duplex() { return true; } virtual StringView purpose() const override { return class_name(); } diff --git a/Kernel/Net/NetworkAdapter.h b/Kernel/Net/NetworkAdapter.h index 2a6b192f7d..ee7c82235d 100644 --- a/Kernel/Net/NetworkAdapter.h +++ b/Kernel/Net/NetworkAdapter.h @@ -42,6 +42,8 @@ struct PacketWithTimestamp : public RefCounted { class NetworkAdapter : public RefCounted , public Weakable { public: + static constexpr i32 LINKSPEED_INVALID = -1; + virtual ~NetworkAdapter(); virtual StringView class_name() const = 0; @@ -53,6 +55,12 @@ public: IPv4Address ipv4_broadcast() const { return IPv4Address { (m_ipv4_address.to_u32() & m_ipv4_netmask.to_u32()) | ~m_ipv4_netmask.to_u32() }; } IPv4Address ipv4_gateway() const { return m_ipv4_gateway; } virtual bool link_up() { return false; } + virtual i32 link_speed() + { + // In Mbit/sec. + return LINKSPEED_INVALID; + } + virtual bool link_full_duplex() { return false; } void set_ipv4_address(const IPv4Address&); void set_ipv4_netmask(const IPv4Address&); diff --git a/Kernel/Net/RTL8139NetworkAdapter.cpp b/Kernel/Net/RTL8139NetworkAdapter.cpp index 567948d1ab..6348651333 100644 --- a/Kernel/Net/RTL8139NetworkAdapter.cpp +++ b/Kernel/Net/RTL8139NetworkAdapter.cpp @@ -29,6 +29,7 @@ namespace Kernel { #define REG_CONFIG1 0x52 #define REG_MSR 0x58 #define REG_BMCR 0x62 +#define REG_ANLPAR 0x68 #define TX_STATUS_OWN 0x2000 #define TX_STATUS_THRESHOLD_MAX 0x3F0000 @@ -84,12 +85,16 @@ namespace Kernel { #define RXCFG_FTH_NONE 0xE000 #define MSR_LINKB 0x02 +#define MSR_SPEED_10 0x08 #define MSR_RX_FLOW_CONTROL_ENABLE 0x40 #define BMCR_SPEED 0x2000 #define BMCR_AUTO_NEGOTIATE 0x1000 #define BMCR_DUPLEX 0x0100 +#define ANLPAR_10FD 0x0040 +#define ANLPAR_TXFD 0x0100 + #define RX_MULTICAST 0x8000 #define RX_PHYSICAL_MATCH 0x4000 #define RX_BROADCAST 0x2000 @@ -366,4 +371,22 @@ u32 RTL8139NetworkAdapter::in32(u16 address) return m_io_base.offset(address).in(); } +bool RTL8139NetworkAdapter::link_full_duplex() +{ + // Note: this code assumes auto-negotiation is enabled (which is now always the case) and + // bases the duplex state on the link partner advertisement. + // If non-auto-negotiation is ever implemented this should be changed. + u16 anlpar = in16(REG_ANLPAR); + return !!(anlpar & (ANLPAR_TXFD | ANLPAR_10FD)); +} + +i32 RTL8139NetworkAdapter::link_speed() +{ + if (!link_up()) + return NetworkAdapter::LINKSPEED_INVALID; + + u16 msr = in16(REG_MSR); + return msr & MSR_SPEED_10 ? 10 : 100; +} + } diff --git a/Kernel/Net/RTL8139NetworkAdapter.h b/Kernel/Net/RTL8139NetworkAdapter.h index 164fbb0c77..d42e6a505e 100644 --- a/Kernel/Net/RTL8139NetworkAdapter.h +++ b/Kernel/Net/RTL8139NetworkAdapter.h @@ -26,6 +26,8 @@ public: virtual void send_raw(ReadonlyBytes) override; virtual bool link_up() override { return m_link_up; } + virtual i32 link_speed() override; + virtual bool link_full_duplex() override; virtual StringView purpose() const override { return class_name(); } diff --git a/Kernel/Net/RTL8168NetworkAdapter.cpp b/Kernel/Net/RTL8168NetworkAdapter.cpp index a1d6c7f763..6563e6555f 100644 --- a/Kernel/Net/RTL8168NetworkAdapter.cpp +++ b/Kernel/Net/RTL8168NetworkAdapter.cpp @@ -172,6 +172,11 @@ namespace Kernel { #define MISC2_PFM_D3COLD_ENABLE 0x40 +#define PHYSTATUS_FULLDUP 0x01 +#define PHYSTATUS_1000MF 0x10 +#define PHYSTATUS_100M 0x08 +#define PHYSTATUS_10M 0x04 + #define TX_BUFFER_SIZE 0x1FF8 #define RX_BUFFER_SIZE 0x1FF8 // FIXME: this should be increased (0x3FFF) @@ -1631,4 +1636,27 @@ String RTL8168NetworkAdapter::possible_device_name() } VERIFY_NOT_REACHED(); } + +bool RTL8168NetworkAdapter::link_full_duplex() +{ + u8 phystatus = in8(REG_PHYSTATUS); + return !!(phystatus & (PHYSTATUS_FULLDUP | PHYSTATUS_1000MF)); +} + +i32 RTL8168NetworkAdapter::link_speed() +{ + if (!link_up()) + return NetworkAdapter::LINKSPEED_INVALID; + + u8 phystatus = in8(REG_PHYSTATUS); + if (phystatus & PHYSTATUS_1000MF) + return 1000; + if (phystatus & PHYSTATUS_100M) + return 100; + if (phystatus & PHYSTATUS_10M) + return 10; + + return NetworkAdapter::LINKSPEED_INVALID; +} + } diff --git a/Kernel/Net/RTL8168NetworkAdapter.h b/Kernel/Net/RTL8168NetworkAdapter.h index 0066e8d23b..ae71976fc9 100644 --- a/Kernel/Net/RTL8168NetworkAdapter.h +++ b/Kernel/Net/RTL8168NetworkAdapter.h @@ -26,6 +26,8 @@ public: virtual void send_raw(ReadonlyBytes) override; virtual bool link_up() override { return m_link_up; } + virtual bool link_full_duplex() override; + virtual i32 link_speed() override; virtual StringView purpose() const override { return class_name(); }