mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 06:27:45 +00:00
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:
parent
15d6b3017a
commit
eb0d56a4ed
2 changed files with 179 additions and 11 deletions
|
@ -38,6 +38,8 @@ namespace Kernel {
|
||||||
#define REG_CSI_DATA 0x64
|
#define REG_CSI_DATA 0x64
|
||||||
#define REG_CSI_ADDR 0x68
|
#define REG_CSI_ADDR 0x68
|
||||||
#define REG_PHYSTATUS 0x6C
|
#define REG_PHYSTATUS 0x6C
|
||||||
|
#define REG_MACDBG 0x6D
|
||||||
|
#define REG_GPIO 0x6E
|
||||||
#define REG_PMCH 0x6F
|
#define REG_PMCH 0x6F
|
||||||
#define REG_ERI_DATA 0x70
|
#define REG_ERI_DATA 0x70
|
||||||
#define REG_ERI_ADDR 0x74
|
#define REG_ERI_ADDR 0x74
|
||||||
|
@ -46,6 +48,7 @@ namespace Kernel {
|
||||||
#define REG_OCP_ADDR 0xB4
|
#define REG_OCP_ADDR 0xB4
|
||||||
#define REG_GPHY_OCP 0xB8
|
#define REG_GPHY_OCP 0xB8
|
||||||
#define REG_DLLPR 0xD0
|
#define REG_DLLPR 0xD0
|
||||||
|
#define REG_DBG 0xD1
|
||||||
#define REG_MCU 0xD3
|
#define REG_MCU 0xD3
|
||||||
#define REG_RMS 0xDA
|
#define REG_RMS 0xDA
|
||||||
#define REG_CPLUS_COMMAND 0xE0
|
#define REG_CPLUS_COMMAND 0xE0
|
||||||
|
@ -61,6 +64,7 @@ namespace Kernel {
|
||||||
#define COMMAND_TX_ENABLE 0x4
|
#define COMMAND_TX_ENABLE 0x4
|
||||||
#define COMMAND_RX_ENABLE 0x8
|
#define COMMAND_RX_ENABLE 0x8
|
||||||
#define COMMAND_RESET 0x10
|
#define COMMAND_RESET 0x10
|
||||||
|
#define COMMAND_STOP 0x80
|
||||||
|
|
||||||
#define CPLUS_COMMAND_VERIFY_CHECKSUM 0x20
|
#define CPLUS_COMMAND_VERIFY_CHECKSUM 0x20
|
||||||
#define CPLUS_COMMAND_VLAN_STRIP 0x40
|
#define CPLUS_COMMAND_VLAN_STRIP 0x40
|
||||||
|
@ -104,6 +108,8 @@ namespace Kernel {
|
||||||
#define RXCFG_MULTI_ENABLE 0x4000
|
#define RXCFG_MULTI_ENABLE 0x4000
|
||||||
#define RXCFG_128INT_ENABLE 0x8000
|
#define RXCFG_128INT_ENABLE 0x8000
|
||||||
|
|
||||||
|
#define CFG1_SPEED_DOWN 0x10
|
||||||
|
|
||||||
#define CFG2_CLOCK_REQUEST_ENABLE 0x80
|
#define CFG2_CLOCK_REQUEST_ENABLE 0x80
|
||||||
|
|
||||||
#define CFG3_BEACON_ENABLE 0x1
|
#define CFG3_BEACON_ENABLE 0x1
|
||||||
|
@ -180,6 +186,11 @@ namespace Kernel {
|
||||||
#define PHYSTATUS_100M 0x08
|
#define PHYSTATUS_100M 0x08
|
||||||
#define PHYSTATUS_10M 0x04
|
#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 TX_BUFFER_SIZE 0x1FF8
|
||||||
#define RX_BUFFER_SIZE 0x1FF8 // FIXME: this should be increased (0x3FFF)
|
#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::Version1:
|
||||||
case ChipVersion::Version2:
|
case ChipVersion::Version2:
|
||||||
case ChipVersion::Version3:
|
case ChipVersion::Version3:
|
||||||
return true;
|
|
||||||
case ChipVersion::Version4:
|
case ChipVersion::Version4:
|
||||||
case ChipVersion::Version5:
|
case ChipVersion::Version5:
|
||||||
case ChipVersion::Version6:
|
case ChipVersion::Version6:
|
||||||
|
return true;
|
||||||
case ChipVersion::Version7:
|
case ChipVersion::Version7:
|
||||||
case ChipVersion::Version8:
|
case ChipVersion::Version8:
|
||||||
case ChipVersion::Version9:
|
case ChipVersion::Version9:
|
||||||
|
@ -325,12 +336,14 @@ UNMAP_AFTER_INIT ErrorOr<void> RTL8168NetworkAdapter::initialize(Badge<Networkin
|
||||||
Processor::wait_check();
|
Processor::wait_check();
|
||||||
}
|
}
|
||||||
|
|
||||||
// software reset
|
|
||||||
reset();
|
|
||||||
|
|
||||||
// clear interrupts
|
// clear interrupts
|
||||||
out16(REG_ISR, 0xffff);
|
out16(REG_ISR, 0xffff);
|
||||||
|
|
||||||
|
pci_commit();
|
||||||
|
|
||||||
|
// software reset
|
||||||
|
reset();
|
||||||
|
|
||||||
enable_bus_mastering(device_identifier());
|
enable_bus_mastering(device_identifier());
|
||||||
|
|
||||||
read_mac_address();
|
read_mac_address();
|
||||||
|
@ -362,6 +375,17 @@ void RTL8168NetworkAdapter::startup()
|
||||||
|
|
||||||
// version specific phy configuration
|
// version specific phy configuration
|
||||||
configure_phy();
|
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
|
// software reset phy
|
||||||
phy_out(PHY_REG_BMCR, phy_in(PHY_REG_BMCR) | BMCR_RESET);
|
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);
|
out16(REG_CPLUS_COMMAND, cplus_command);
|
||||||
in16(REG_CPLUS_COMMAND); // C+ Command barrier
|
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
|
// power up phy
|
||||||
if (m_version >= ChipVersion::Version9 && m_version <= ChipVersion::Version15) {
|
if (m_version >= ChipVersion::Version9 && m_version <= ChipVersion::Version15) {
|
||||||
out8(REG_PMCH, in8(REG_PMCH) | 0x80);
|
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)
|
phy_out(PHY_REG_BMCR, BMCR_AUTO_NEGOTIATE); // send known good phy write (acts as a phy barrier)
|
||||||
start_hardware();
|
start_hardware();
|
||||||
|
pci_commit();
|
||||||
|
|
||||||
// re-enable interrupts
|
// re-enable interrupts
|
||||||
auto enabled_interrupts = INT_RXOK | INT_RXERR | INT_TXOK | INT_TXERR | INT_RX_OVERFLOW | INT_LINK_CHANGE | INT_SYS_ERR;
|
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;
|
enabled_interrupts &= ~INT_RX_OVERFLOW;
|
||||||
}
|
}
|
||||||
out16(REG_IMR, enabled_interrupts);
|
out16(REG_IMR, enabled_interrupts);
|
||||||
|
pci_commit();
|
||||||
|
|
||||||
// update link status
|
// update link status
|
||||||
m_link_up = (in8(REG_PHYSTATUS) & PHY_LINK_STATUS) != 0;
|
m_link_up = (in8(REG_PHYSTATUS) & PHY_LINK_STATUS) != 0;
|
||||||
|
@ -420,11 +453,14 @@ void RTL8168NetworkAdapter::configure_phy()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case ChipVersion::Version4:
|
case ChipVersion::Version4:
|
||||||
TODO();
|
configure_phy_c_1();
|
||||||
|
return;
|
||||||
case ChipVersion::Version5:
|
case ChipVersion::Version5:
|
||||||
TODO();
|
configure_phy_c_2();
|
||||||
|
return;
|
||||||
case ChipVersion::Version6:
|
case ChipVersion::Version6:
|
||||||
TODO();
|
configure_phy_c_3();
|
||||||
|
return;
|
||||||
case ChipVersion::Version7:
|
case ChipVersion::Version7:
|
||||||
TODO();
|
TODO();
|
||||||
case ChipVersion::Version8:
|
case ChipVersion::Version8:
|
||||||
|
@ -510,6 +546,79 @@ void RTL8168NetworkAdapter::configure_phy_b_2()
|
||||||
phy_out_batch(phy_registers);
|
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()
|
void RTL8168NetworkAdapter::configure_phy_e_2()
|
||||||
{
|
{
|
||||||
// FIXME: linux's driver writes a firmware blob to the device at this point, is this needed?
|
// 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()
|
void RTL8168NetworkAdapter::start_hardware()
|
||||||
{
|
{
|
||||||
|
|
||||||
// unlock config registers
|
// unlock config registers
|
||||||
out8(REG_CFG9346, CFG9346_UNLOCK);
|
out8(REG_CFG9346, CFG9346_UNLOCK);
|
||||||
|
|
||||||
|
@ -832,6 +940,7 @@ void RTL8168NetworkAdapter::start_hardware()
|
||||||
|
|
||||||
// enable rx/tx
|
// enable rx/tx
|
||||||
out8(REG_COMMAND, COMMAND_RX_ENABLE | COMMAND_TX_ENABLE);
|
out8(REG_COMMAND, COMMAND_RX_ENABLE | COMMAND_TX_ENABLE);
|
||||||
|
pci_commit();
|
||||||
|
|
||||||
// turn on all multicast
|
// turn on all multicast
|
||||||
out32(REG_MAR0, 0xFFFFFFFF);
|
out32(REG_MAR0, 0xFFFFFFFF);
|
||||||
|
@ -855,11 +964,14 @@ void RTL8168NetworkAdapter::hardware_quirks()
|
||||||
hardware_quirks_b_2();
|
hardware_quirks_b_2();
|
||||||
return;
|
return;
|
||||||
case ChipVersion::Version4:
|
case ChipVersion::Version4:
|
||||||
TODO();
|
hardware_quirks_c_1();
|
||||||
|
return;
|
||||||
case ChipVersion::Version5:
|
case ChipVersion::Version5:
|
||||||
TODO();
|
hardware_quirks_c_2();
|
||||||
|
return;
|
||||||
case ChipVersion::Version6:
|
case ChipVersion::Version6:
|
||||||
TODO();
|
hardware_quirks_c_3();
|
||||||
|
return;
|
||||||
case ChipVersion::Version7:
|
case ChipVersion::Version7:
|
||||||
TODO();
|
TODO();
|
||||||
case ChipVersion::Version8:
|
case ChipVersion::Version8:
|
||||||
|
@ -933,6 +1045,49 @@ void RTL8168NetworkAdapter::hardware_quirks_b_2()
|
||||||
out8(REG_CONFIG4, in8(REG_CONFIG4) & ~1);
|
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()
|
void RTL8168NetworkAdapter::hardware_quirks_e_2()
|
||||||
{
|
{
|
||||||
static constexpr auto ephy_info = to_array<EPhyUpdate>({
|
static constexpr auto ephy_info = to_array<EPhyUpdate>({
|
||||||
|
@ -1186,6 +1341,12 @@ void RTL8168NetworkAdapter::reset()
|
||||||
Processor::wait_check();
|
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()
|
UNMAP_AFTER_INIT void RTL8168NetworkAdapter::read_mac_address()
|
||||||
{
|
{
|
||||||
MACAddress mac {};
|
MACAddress mac {};
|
||||||
|
|
|
@ -129,6 +129,7 @@ private:
|
||||||
StringView possible_device_name();
|
StringView possible_device_name();
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
void pci_commit();
|
||||||
void read_mac_address();
|
void read_mac_address();
|
||||||
void set_phy_speed();
|
void set_phy_speed();
|
||||||
void start_hardware();
|
void start_hardware();
|
||||||
|
@ -137,6 +138,9 @@ private:
|
||||||
void configure_phy();
|
void configure_phy();
|
||||||
void configure_phy_b_1();
|
void configure_phy_b_1();
|
||||||
void configure_phy_b_2();
|
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_e_2();
|
||||||
void configure_phy_h_1();
|
void configure_phy_h_1();
|
||||||
void configure_phy_h_2();
|
void configure_phy_h_2();
|
||||||
|
@ -146,6 +150,9 @@ private:
|
||||||
void hardware_quirks();
|
void hardware_quirks();
|
||||||
void hardware_quirks_b_1();
|
void hardware_quirks_b_1();
|
||||||
void hardware_quirks_b_2();
|
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_e_2();
|
||||||
void hardware_quirks_h();
|
void hardware_quirks_h();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue