Kernel/Net: Implement support for RTL8168C

Please be aware that I only have NIC with chip version 6 so
this is the only one that I have tested. Rest was implemented
via looking at Linux rtl8169 driver. Also thanks to IdanHo
for some initial work.
This commit is contained in:
mrkubax10 2024-02-18 20:07:39 +01:00 committed by Andrew Kaster
parent 15d6b3017a
commit eb0d56a4ed
2 changed files with 179 additions and 11 deletions

View file

@ -38,6 +38,8 @@ namespace Kernel {
#define REG_CSI_DATA 0x64
#define REG_CSI_ADDR 0x68
#define REG_PHYSTATUS 0x6C
#define REG_MACDBG 0x6D
#define REG_GPIO 0x6E
#define REG_PMCH 0x6F
#define REG_ERI_DATA 0x70
#define REG_ERI_ADDR 0x74
@ -46,6 +48,7 @@ namespace Kernel {
#define REG_OCP_ADDR 0xB4
#define REG_GPHY_OCP 0xB8
#define REG_DLLPR 0xD0
#define REG_DBG 0xD1
#define REG_MCU 0xD3
#define REG_RMS 0xDA
#define REG_CPLUS_COMMAND 0xE0
@ -61,6 +64,7 @@ namespace Kernel {
#define COMMAND_TX_ENABLE 0x4
#define COMMAND_RX_ENABLE 0x8
#define COMMAND_RESET 0x10
#define COMMAND_STOP 0x80
#define CPLUS_COMMAND_VERIFY_CHECKSUM 0x20
#define CPLUS_COMMAND_VLAN_STRIP 0x40
@ -104,6 +108,8 @@ namespace Kernel {
#define RXCFG_MULTI_ENABLE 0x4000
#define RXCFG_128INT_ENABLE 0x8000
#define CFG1_SPEED_DOWN 0x10
#define CFG2_CLOCK_REQUEST_ENABLE 0x80
#define CFG3_BEACON_ENABLE 0x1
@ -180,6 +186,11 @@ namespace Kernel {
#define PHYSTATUS_100M 0x08
#define PHYSTATUS_10M 0x04
#define GPIO_ENABLE 0x1
#define DBG_FIX_NAK_2 0x8
#define DBG_FIX_NAK_1 0x10
#define TX_BUFFER_SIZE 0x1FF8
#define RX_BUFFER_SIZE 0x1FF8 // FIXME: this should be increased (0x3FFF)
@ -206,10 +217,10 @@ bool RTL8168NetworkAdapter::determine_supported_version() const
case ChipVersion::Version1:
case ChipVersion::Version2:
case ChipVersion::Version3:
return true;
case ChipVersion::Version4:
case ChipVersion::Version5:
case ChipVersion::Version6:
return true;
case ChipVersion::Version7:
case ChipVersion::Version8:
case ChipVersion::Version9:
@ -325,12 +336,14 @@ UNMAP_AFTER_INIT ErrorOr<void> RTL8168NetworkAdapter::initialize(Badge<Networkin
Processor::wait_check();
}
// software reset
reset();
// clear interrupts
out16(REG_ISR, 0xffff);
pci_commit();
// software reset
reset();
enable_bus_mastering(device_identifier());
read_mac_address();
@ -362,6 +375,17 @@ void RTL8168NetworkAdapter::startup()
// version specific phy configuration
configure_phy();
pci_commit();
// disable interrupts
out16(REG_IMR, 0);
out16(REG_ISR, 0xffff);
pci_commit();
// send stop command
out8(REG_COMMAND, COMMAND_STOP);
reset();
// software reset phy
phy_out(PHY_REG_BMCR, phy_in(PHY_REG_BMCR) | BMCR_RESET);
@ -375,6 +399,13 @@ void RTL8168NetworkAdapter::startup()
out16(REG_CPLUS_COMMAND, cplus_command);
in16(REG_CPLUS_COMMAND); // C+ Command barrier
if (m_version == ChipVersion::Version5 || m_version == ChipVersion::Version6) {
if (in8(REG_MACDBG) & 0x80)
out8(REG_GPIO, in8(REG_GPIO) | GPIO_ENABLE);
else
out8(REG_GPIO, in8(REG_GPIO) & ~GPIO_ENABLE);
}
// power up phy
if (m_version >= ChipVersion::Version9 && m_version <= ChipVersion::Version15) {
out8(REG_PMCH, in8(REG_PMCH) | 0x80);
@ -393,6 +424,7 @@ void RTL8168NetworkAdapter::startup()
}
phy_out(PHY_REG_BMCR, BMCR_AUTO_NEGOTIATE); // send known good phy write (acts as a phy barrier)
start_hardware();
pci_commit();
// re-enable interrupts
auto enabled_interrupts = INT_RXOK | INT_RXERR | INT_TXOK | INT_TXERR | INT_RX_OVERFLOW | INT_LINK_CHANGE | INT_SYS_ERR;
@ -401,6 +433,7 @@ void RTL8168NetworkAdapter::startup()
enabled_interrupts &= ~INT_RX_OVERFLOW;
}
out16(REG_IMR, enabled_interrupts);
pci_commit();
// update link status
m_link_up = (in8(REG_PHYSTATUS) & PHY_LINK_STATUS) != 0;
@ -420,11 +453,14 @@ void RTL8168NetworkAdapter::configure_phy()
return;
}
case ChipVersion::Version4:
TODO();
configure_phy_c_1();
return;
case ChipVersion::Version5:
TODO();
configure_phy_c_2();
return;
case ChipVersion::Version6:
TODO();
configure_phy_c_3();
return;
case ChipVersion::Version7:
TODO();
case ChipVersion::Version8:
@ -510,6 +546,79 @@ void RTL8168NetworkAdapter::configure_phy_b_2()
phy_out_batch(phy_registers);
}
void RTL8168NetworkAdapter::configure_phy_c_1()
{
static constexpr auto phy_registers = to_array<PhyRegister>({
{ 0x1f, 0x0001 },
{ 0x12, 0x2300 },
{ 0x1f, 0x0002 },
{ 0x00, 0x88d4 },
{ 0x01, 0x82b1 },
{ 0x03, 0x7002 },
{ 0x08, 0x9e30 },
{ 0x09, 0x01f0 },
{ 0x0a, 0x5500 },
{ 0x0c, 0x00c8 },
{ 0x1f, 0x0003 },
{ 0x12, 0xc096 },
{ 0x16, 0x000a },
{ 0x1f, 0x0000 },
{ 0x1f, 0x0000 },
{ 0x09, 0x2000 },
{ 0x09, 0x0000 },
});
phy_out_batch(phy_registers);
phy_update(0x14, 1 << 5, 0);
phy_update(0x0d, 1 << 5, 0);
}
void RTL8168NetworkAdapter::configure_phy_c_2()
{
static constexpr auto phy_registers = to_array<PhyRegister>({
{ 0x1f, 0x0001 },
{ 0x12, 0x2300 },
{ 0x03, 0x802f },
{ 0x02, 0x4f02 },
{ 0x01, 0x0409 },
{ 0x00, 0xf099 },
{ 0x04, 0x9800 },
{ 0x04, 0x9000 },
{ 0x1d, 0x3d98 },
{ 0x1f, 0x0002 },
{ 0x0c, 0x7eb8 },
{ 0x06, 0x0761 },
{ 0x1f, 0x0003 },
{ 0x16, 0x0f0a },
{ 0x1f, 0x0000 },
});
phy_out_batch(phy_registers);
phy_update(0x16, 0x1, 0);
phy_update(0x14, 1 << 5, 0);
phy_update(0x0d, 1 << 5, 0);
}
void RTL8168NetworkAdapter::configure_phy_c_3()
{
static constexpr auto phy_registers = to_array<PhyRegister>({
{ 0x1f, 0x0001 },
{ 0x12, 0x2300 },
{ 0x1d, 0x3d98 },
{ 0x1f, 0x0002 },
{ 0x0c, 0x7eb8 },
{ 0x06, 0x5461 },
{ 0x1f, 0x0003 },
{ 0x16, 0x0f0a },
{ 0x1f, 0x0000 },
});
phy_out_batch(phy_registers);
phy_update(0x16, 0x1, 0);
phy_update(0x14, 1 << 5, 0);
phy_update(0x0d, 1 << 5, 0);
}
void RTL8168NetworkAdapter::configure_phy_e_2()
{
// FIXME: linux's driver writes a firmware blob to the device at this point, is this needed?
@ -794,7 +903,6 @@ void RTL8168NetworkAdapter::rar_exgmac_set()
void RTL8168NetworkAdapter::start_hardware()
{
// unlock config registers
out8(REG_CFG9346, CFG9346_UNLOCK);
@ -832,6 +940,7 @@ void RTL8168NetworkAdapter::start_hardware()
// enable rx/tx
out8(REG_COMMAND, COMMAND_RX_ENABLE | COMMAND_TX_ENABLE);
pci_commit();
// turn on all multicast
out32(REG_MAR0, 0xFFFFFFFF);
@ -855,11 +964,14 @@ void RTL8168NetworkAdapter::hardware_quirks()
hardware_quirks_b_2();
return;
case ChipVersion::Version4:
TODO();
hardware_quirks_c_1();
return;
case ChipVersion::Version5:
TODO();
hardware_quirks_c_2();
return;
case ChipVersion::Version6:
TODO();
hardware_quirks_c_3();
return;
case ChipVersion::Version7:
TODO();
case ChipVersion::Version8:
@ -933,6 +1045,49 @@ void RTL8168NetworkAdapter::hardware_quirks_b_2()
out8(REG_CONFIG4, in8(REG_CONFIG4) & ~1);
}
void RTL8168NetworkAdapter::hardware_quirks_c_1()
{
csi_enable(CSI_ACCESS_2);
out8(REG_DBG, 0x06 | DBG_FIX_NAK_1 | DBG_FIX_NAK_2);
static constexpr auto ephy_info = to_array<EPhyUpdate>({
{ 0x02, 0x0800, 0x1000 },
{ 0x03, 0, 0x0002 },
{ 0x06, 0x0080, 0x0000 },
});
extended_phy_initialize(ephy_info);
out8(REG_CONFIG1, in8(REG_CONFIG1) | CFG1_SPEED_DOWN);
out8(REG_CONFIG3, in8(REG_CONFIG3) & ~CFG3_BEACON_ENABLE);
}
void RTL8168NetworkAdapter::hardware_quirks_c_2()
{
csi_enable(CSI_ACCESS_2);
static constexpr auto ephy_info = to_array<EPhyUpdate>({
{ 0x01, 0, 0x1 },
{ 0x03, 0x0400, 0x0020 },
});
extended_phy_initialize(ephy_info);
out8(REG_CONFIG1, in8(REG_CONFIG1) | CFG1_SPEED_DOWN);
out8(REG_CONFIG3, in8(REG_CONFIG3) | CFG3_BEACON_ENABLE);
// FIXME: Disable PCIe clock request
}
void RTL8168NetworkAdapter::hardware_quirks_c_3()
{
csi_enable(CSI_ACCESS_2);
out8(REG_CONFIG1, in8(REG_CONFIG1) | CFG1_SPEED_DOWN);
out8(REG_CONFIG3, in8(REG_CONFIG3) & ~CFG3_BEACON_ENABLE);
// FIXME: Disable PCIe clock request
}
void RTL8168NetworkAdapter::hardware_quirks_e_2()
{
static constexpr auto ephy_info = to_array<EPhyUpdate>({
@ -1186,6 +1341,12 @@ void RTL8168NetworkAdapter::reset()
Processor::wait_check();
}
void RTL8168NetworkAdapter::pci_commit()
{
// read any register to commit previous PCI write
in8(REG_COMMAND);
}
UNMAP_AFTER_INIT void RTL8168NetworkAdapter::read_mac_address()
{
MACAddress mac {};

View file

@ -129,6 +129,7 @@ private:
StringView possible_device_name();
void reset();
void pci_commit();
void read_mac_address();
void set_phy_speed();
void start_hardware();
@ -137,6 +138,9 @@ private:
void configure_phy();
void configure_phy_b_1();
void configure_phy_b_2();
void configure_phy_c_1();
void configure_phy_c_2();
void configure_phy_c_3();
void configure_phy_e_2();
void configure_phy_h_1();
void configure_phy_h_2();
@ -146,6 +150,9 @@ private:
void hardware_quirks();
void hardware_quirks_b_1();
void hardware_quirks_b_2();
void hardware_quirks_c_1();
void hardware_quirks_c_2();
void hardware_quirks_c_3();
void hardware_quirks_e_2();
void hardware_quirks_h();