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.
This commit is contained in:
Thomas Wagenveld 2021-07-25 20:16:42 +02:00 committed by Gunnar Beutner
parent 238ac8ac25
commit 59fdeec7f5
9 changed files with 98 additions and 0 deletions

View file

@ -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);
}
}

View file

@ -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(); }

View file

@ -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; }
};
}

View file

@ -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(); }

View file

@ -42,6 +42,8 @@ struct PacketWithTimestamp : public RefCounted<PacketWithTimestamp> {
class NetworkAdapter : public RefCounted<NetworkAdapter>
, public Weakable<NetworkAdapter> {
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&);

View file

@ -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<u32>();
}
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;
}
}

View file

@ -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(); }

View file

@ -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;
}
}

View file

@ -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(); }