mirror of
https://github.com/RGBCube/serenity
synced 2025-05-14 05:44:58 +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_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 {};
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue