浏览代码

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.
mrkubax10 1 年之前
父节点
当前提交
eb0d56a4ed
共有 2 个文件被更改,包括 179 次插入11 次删除
  1. 172 11
      Kernel/Net/Realtek/RTL8168NetworkAdapter.cpp
  2. 7 0
      Kernel/Net/Realtek/RTL8168NetworkAdapter.h

+ 172 - 11
Kernel/Net/Realtek/RTL8168NetworkAdapter.cpp

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

+ 7 - 0
Kernel/Net/Realtek/RTL8168NetworkAdapter.h

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