| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/09/29 07:21 | flow | patch-triage |
3mArgs:null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"KMSANReasoning": "",
"NeedsKMSAN": false,
"Reasoning": "The patch modifies the Realtek r8169 Ethernet driver (drivers/net/ethernet/realtek/r8169_main.c) to add multi-queue RSS and MSI-X support for RTL8127 PCIe NICs. Realtek r8169/r8125/r8127 devices require physical PCIe hardware that is not emulated in standard QEMU or virtualized fuzzing environments (QEMU only emulates the legacy RTL8139 device handled by 8139cp/8139too). Therefore, the modified driver code is structurally unreachable in standard fuzzing environments.",
"WorthFuzzing": false
} |
| 1/1 | 2026/09/29 07:21 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 02191112044d1fe624bd6629e242a4a9e4a02a7d\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Tue Sep 29 07:21:08 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c\nindex 5415ff62a2869..7c27254218cce 100644\n--- a/drivers/net/ethernet/realtek/r8169_main.c\n+++ b/drivers/net/ethernet/realtek/r8169_main.c\n@@ -30,6 +30,7 @@\n #include \u003clinux/prefetch.h\u003e\n #include \u003clinux/ipv6.h\u003e\n #include \u003clinux/unaligned.h\u003e\n+#include \u003clinux/u64_stats_sync.h\u003e\n #include \u003cnet/ip6_checksum.h\u003e\n #include \u003cnet/netdev_queues.h\u003e\n \n@@ -74,9 +75,26 @@\n #define NUM_TX_DESC\t256\t/* Number of Tx descriptor registers */\n #define NUM_RX_DESC\t256\t/* Number of Rx descriptor registers */\n #define R8169_TX_RING_BYTES\t(NUM_TX_DESC * sizeof(struct TxDesc))\n+\n #define R8169_RX_RING_BYTES\t(NUM_RX_DESC * sizeof(struct RxDesc))\n #define R8169_TX_STOP_THRS\t(MAX_SKB_FRAGS + 1)\n #define R8169_TX_START_THRS\t(2 * R8169_TX_STOP_THRS)\n+#define R8169_MAX_RX_QUEUES\t8\n+#define R8169_DEFAULT_RX_QUEUES\t1\n+#define R8169_MAX_TX_QUEUES\t1\n+#define R8127_MAX_NUM_IRQVEC\t32\n+#define R8127_MIN_NUM_IRQVEC\t30\n+#define R8169_IRQ_DEFAULT\t1\n+#define RTL_RSS_KEY_SIZE\t40\n+#define RSS_CPU_NUM_MASK\tGENMASK(18, 16)\n+#define RSS_HASH_MASK\t\tGENMASK(10, 8)\n+#define RTL_MAX_INDIRECTION_TABLE_ENTRIES 128\n+#define RXS_RSS_UDP\t\tBIT(27)\n+#define RXS_RSS_IPV4\t\tBIT(28)\n+#define RXS_RSS_IPV6\t\tBIT(29)\n+#define RXS_RSS_TCP\t\tBIT(30)\n+#define RXS_RSS_L3_TYPE_MASK\t(RXS_RSS_IPV4 | RXS_RSS_IPV6)\n+#define RXS_RSS_L4_TYPE_MASK\t(RXS_RSS_TCP | RXS_RSS_UDP)\n \n #define OCP_STD_PHY_BASE\t0xa400\n \n@@ -463,11 +481,16 @@ enum rtl8125_registers {\n \tTxPoll_8125\t\t= 0x90,\n \tLEDSEL3\t\t\t= 0x96,\n \tMAC0_BKP\t\t= 0x19e0,\n+\tRDSAR_Q1_LOW\t\t= 0x4000,\n \tRSS_CTRL_8125\t\t= 0x4500,\n \tQ_NUM_CTRL_8125\t\t= 0x4800,\n \tEEE_TXIDLE_TIMER_8125\t= 0x6048,\n+\tIMR_CLEAR_VEC_MAP_REG\t= 0x0d00,\n+\tISR_VEC_MAP_REG\t\t= 0x0d04,\n+\tIMR_SET_VEC_MAP_REG\t= 0x0d0c,\n };\n \n+#define MSIX_ID_VEC_MAP_LINKCHG\t29\n #define LEDSEL_MASK_8125\t0x23f\n \n #define RX_VLAN_INNER_8125\tBIT(22)\n@@ -496,6 +519,9 @@ enum rtl_register_content {\n \tRxRUNT\t= (1 \u003c\u003c 20),\n \tRxCRC\t= (1 \u003c\u003c 19),\n \n+\tRXRUNT_RSS\t= (1 \u003c\u003c 21),\n+\tRXCRC_RSS\t= (1 \u003c\u003c 20),\n+\n \t/* ChipCmdBits */\n \tStopReq\t\t= 0x80,\n \tCmdReset\t= 0x10,\n@@ -598,6 +624,23 @@ enum rtl_register_content {\n \n \t/* magic enable v2 */\n \tMagicPacket_v2\t= (1 \u003c\u003c 16),\t/* Wake up when receives a Magic Packet */\n+#define\tISRIMR_LINKCHG\tBIT(29)\n+#define\tISRIMR_TOK_Q0\tBIT(8)\n+#define\tISRIMR_ROK_Q0\tBIT(0)\n+#define RTL_DESC_TYPE_CTRL\t\t0xd8\n+#define RSS_KEY_REG\t\t\t0x4600\n+#define RSS_INDIRECTION_TBL_REG\t\t0x4700\n+#define RSS_CTRL_TCP_IPV4_SUPP\t\tBIT(0)\n+#define RTL_DESC_TYPE_RSS\t\tBIT(1)\n+#define RSS_CTRL_IPV4_SUPP\t\tBIT(1)\n+#define RSS_CTRL_TCP_IPV6_SUPP\t\tBIT(2)\n+#define RSS_CTRL_IPV6_SUPP\t\tBIT(3)\n+#define RSS_CTRL_IPV6_EXT_SUPP\t\tBIT(4)\n+#define RSS_CTRL_TCP_IPV6_EXT_SUPP\tBIT(5)\n+#define RSS_CTRL_UDP_IPV4_SUPP\t\tBIT(11)\n+#define RSS_CTRL_UDP_IPV6_SUPP\t\tBIT(12)\n+#define\tRX_RES_RSS\t\t\tBIT(22)\n+#define RTL_RX_Q_NUM_MASK\t\tGENMASK(4, 2)\n };\n \n enum rtl_desc_bit {\n@@ -655,6 +698,11 @@ enum rtl_rx_desc_bit {\n #define RxProtoIP\t(PID1 | PID0)\n #define RxProtoMask\tRxProtoIP\n \n+#define\tRX_UDPT_DESC_RSS\tBIT(19)\n+#define\tRX_TCPT_DESC_RSS\tBIT(18)\n+#define\tRX_UDPF_DESC_RSS\tBIT(16) /* UDP/IP checksum failed */\n+#define\tRX_TCPF_DESC_RSS\tBIT(15) /* TCP/IP checksum failed */\n+\n \tIPFail\t\t= (1 \u003c\u003c 16), /* IP checksum failed */\n \tUDPFail\t\t= (1 \u003c\u003c 15), /* UDP/IP checksum failed */\n \tTCPFail\t\t= (1 \u003c\u003c 14), /* TCP/IP checksum failed */\n@@ -676,9 +724,27 @@ struct TxDesc {\n };\n \n struct RxDesc {\n-\t__le32 opts1;\n-\t__le32 opts2;\n-\t__le64 addr;\n+\tunion {\n+\t\t/* RX_DESC_TYPE_DEFAULT */\n+\t\tstruct {\n+\t\t\t__le32 opts1;\n+\t\t\t__le32 opts2;\n+\t\t\t__le64 addr;\n+\t\t};\n+\n+\t\t/* RX_DESC_TYPE_RSS */\n+\t\tstruct {\n+\t\t\tunion {\n+\t\t\t\t__le64 rss_addr;\n+\t\t\t\tstruct {\n+\t\t\t\t\t__le32 rss_info;\n+\t\t\t\t\t__le32 rss_result;\n+\t\t\t\t} rss_dword;\n+\t\t\t};\n+\t\t\t__le32 rss_opts2;\n+\t\t\t__le32 rss_opts1;\n+\t\t};\n+\t};\n };\n \n struct ring_info {\n@@ -750,34 +816,63 @@ enum rtl_dash_type {\n \tRTL_DASH_25_BP,\n };\n \n+enum rx_desc_type {\n+\tRX_DESC_TYPE_DEFAULT,\n+\tRX_DESC_TYPE_RSS,\n+};\n+\n+struct rtl8169_rx_ring {\n+\tu32 cur_rx;\n+\tstruct RxDesc *rx_desc_array;\n+\tdma_addr_t rx_desc_phy_addr[NUM_RX_DESC];\n+\tdma_addr_t rx_phy_addr;\n+\tstruct page *rx_databuff[NUM_RX_DESC];\n+\n+\tstruct {\n+\t\tu64 rx_errors;\n+\t\tu64 rx_dropped;\n+\t\tu64 rx_length_errors;\n+\t\tu64 rx_crc_errors;\n+\t\tu64 multicast;\n+\t\tstruct u64_stats_sync syncp;\n+\t} stats;\n+};\n+\n enum rtl_sfp_mode {\n \tRTL_SFP_NONE,\n \tRTL_SFP_8168_AF,\n \tRTL_SFP_8127_ATF,\n };\n \n+struct rtl8169_rss_data {\n+\tu8 rss_key[RTL_RSS_KEY_SIZE];\n+\tu8 rss_indir_tbl[RTL_MAX_INDIRECTION_TABLE_ENTRIES];\n+\tunsigned int hw_supp_indir_tbl_entries;\n+};\n+\n struct rtl8169_private {\n \tvoid __iomem *mmio_addr;\t/* memory map physical address */\n \tstruct pci_dev *pci_dev;\n \tstruct net_device *dev;\n \tstruct phy_device *phydev;\n-\tstruct napi_struct napi;\n \tenum mac_version mac_version;\n \tenum rtl_dash_type dash_type;\n \tenum rtl_sfp_mode sfp_mode;\n-\tu32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */\n \tu32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */\n \tu32 dirty_tx;\n \tstruct TxDesc *TxDescArray;\t/* 256-aligned Tx descriptor ring */\n-\tstruct RxDesc *RxDescArray;\t/* 256-aligned Rx descriptor ring */\n \tdma_addr_t TxPhyAddr;\n-\tdma_addr_t RxPhyAddr;\n-\tstruct page *Rx_databuff[NUM_RX_DESC];\t/* Rx data buffers */\n \tstruct ring_info tx_skb[NUM_TX_DESC];\t/* Tx data buffers */\n+\tstruct napi_struct *rtl8169_napi;\n+\tstruct rtl8169_rx_ring *rx_ring;\n+\tunsigned int num_rx_rings;\n \tu16 cp_cmd;\n \tu16 tx_lpi_timer;\n \tu32 irq_mask;\n-\tint irq;\n+\tunsigned int hw_supp_num_rx_queues;\n+\tstruct rtl8169_rss_data *rss_data;\n+\tunsigned int irq_nvecs;\n+\tenum rx_desc_type init_rx_desc_type;\n \tstruct clk *clk;\n \tint speed;\n \n@@ -1692,6 +1787,11 @@ static enum rtl_sfp_mode rtl_get_sfp_mode(struct rtl8169_private *tp)\n \treturn RTL_SFP_NONE;\n }\n \n+static bool rtl_hw_support_rss(struct rtl8169_private *tp)\n+{\n+\treturn tp-\u003emac_version == RTL_GIGA_MAC_VER_80;\n+}\n+\n static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private *tp)\n {\n \tswitch (tp-\u003emac_version) {\n@@ -1758,26 +1858,38 @@ static u32 rtl_get_events(struct rtl8169_private *tp)\n \n static void rtl_ack_events(struct rtl8169_private *tp, u32 bits)\n {\n-\tif (rtl_is_8125(tp))\n-\t\tRTL_W32(tp, IntrStatus_8125, bits);\n-\telse\n+\tif (rtl_is_8125(tp)) {\n+\t\tif (tp-\u003eirq_nvecs \u003e 1)\n+\t\t\tRTL_W32(tp, ISR_VEC_MAP_REG, bits);\n+\t\telse\n+\t\t\tRTL_W32(tp, IntrStatus_8125, bits);\n+\t} else {\n \t\tRTL_W16(tp, IntrStatus, bits);\n+\t}\n }\n \n static void rtl_irq_disable(struct rtl8169_private *tp)\n {\n-\tif (rtl_is_8125(tp))\n-\t\tRTL_W32(tp, IntrMask_8125, 0);\n-\telse\n+\tif (rtl_is_8125(tp)) {\n+\t\tif (tp-\u003eirq_nvecs \u003e 1)\n+\t\t\tRTL_W32(tp, IMR_CLEAR_VEC_MAP_REG, 0xffffffff);\n+\t\telse\n+\t\t\tRTL_W32(tp, IntrMask_8125, 0);\n+\t} else {\n \t\tRTL_W16(tp, IntrMask, 0);\n+\t}\n }\n \n static void rtl_irq_enable(struct rtl8169_private *tp)\n {\n-\tif (rtl_is_8125(tp))\n-\t\tRTL_W32(tp, IntrMask_8125, tp-\u003eirq_mask);\n-\telse\n+\tif (rtl_is_8125(tp)) {\n+\t\tif (tp-\u003eirq_nvecs \u003e 1)\n+\t\t\tRTL_W32(tp, IMR_SET_VEC_MAP_REG, tp-\u003eirq_mask);\n+\t\telse\n+\t\t\tRTL_W32(tp, IntrMask_8125, tp-\u003eirq_mask);\n+\t} else {\n \t\tRTL_W16(tp, IntrMask, tp-\u003eirq_mask);\n+\t}\n }\n \n static void rtl8169_irq_mask_and_ack(struct rtl8169_private *tp)\n@@ -1979,9 +2091,20 @@ static inline u32 rtl8169_tx_vlan_tag(struct sk_buff *skb)\n \t\tTxVlanTag | swab16(skb_vlan_tag_get(skb)) : 0x00;\n }\n \n-static void rtl8169_rx_vlan_tag(struct RxDesc *desc, struct sk_buff *skb)\n+static void rtl8169_rx_vlan_tag(struct rtl8169_private *tp,\n+\t\t\t\tstruct RxDesc *desc,\n+\t\t\t\tstruct sk_buff *skb)\n {\n-\tu32 opts2 = le32_to_cpu(desc-\u003eopts2);\n+\tu32 opts2;\n+\n+\tswitch (tp-\u003einit_rx_desc_type) {\n+\tcase RX_DESC_TYPE_RSS:\n+\t\topts2 = le32_to_cpu(desc-\u003erss_opts2);\n+\t\tbreak;\n+\tdefault:\n+\t\topts2 = le32_to_cpu(desc-\u003eopts2);\n+\t\tbreak;\n+\t}\n \n \tif (opts2 \u0026 RxVlanTag)\n \t\t__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), swab16(opts2 \u0026 0xffff));\n@@ -2514,34 +2637,6 @@ static int rtl8169_nway_reset(struct net_device *dev)\n \treturn phylink_ethtool_nway_reset(tp-\u003ephylink);\n }\n \n-static const struct ethtool_ops rtl8169_ethtool_ops = {\n-\t.supported_coalesce_params = ETHTOOL_COALESCE_USECS |\n-\t\t\t\t ETHTOOL_COALESCE_MAX_FRAMES,\n-\t.get_drvinfo\t\t= rtl8169_get_drvinfo,\n-\t.get_regs_len\t\t= rtl8169_get_regs_len,\n-\t.get_link\t\t= ethtool_op_get_link,\n-\t.get_coalesce\t\t= rtl_get_coalesce,\n-\t.set_coalesce\t\t= rtl_set_coalesce,\n-\t.get_regs\t\t= rtl8169_get_regs,\n-\t.get_wol\t\t= rtl8169_get_wol,\n-\t.set_wol\t\t= rtl8169_set_wol,\n-\t.get_strings\t\t= rtl8169_get_strings,\n-\t.get_sset_count\t\t= rtl8169_get_sset_count,\n-\t.get_ethtool_stats\t= rtl8169_get_ethtool_stats,\n-\t.get_ts_info\t\t= ethtool_op_get_ts_info,\n-\t.nway_reset\t\t= rtl8169_nway_reset,\n-\t.get_eee\t\t= rtl8169_get_eee,\n-\t.set_eee\t\t= rtl8169_set_eee,\n-\t.get_link_ksettings\t= rtl8169_get_link_ksettings,\n-\t.set_link_ksettings\t= rtl8169_set_link_ksettings,\n-\t.get_ringparam\t\t= rtl8169_get_ringparam,\n-\t.get_pause_stats\t= rtl8169_get_pause_stats,\n-\t.get_pauseparam\t\t= rtl8169_get_pauseparam,\n-\t.set_pauseparam\t\t= rtl8169_set_pauseparam,\n-\t.get_eth_mac_stats\t= rtl8169_get_eth_mac_stats,\n-\t.get_eth_ctrl_stats\t= rtl8169_get_eth_ctrl_stats,\n-};\n-\n static const struct rtl_chip_info *rtl8169_get_chip_version(u32 xid, bool gmii)\n {\n \t/* Chips combining a 1Gbps MAC with a 100Mbps PHY */\n@@ -2717,9 +2812,25 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp)\n \t}\n }\n \n+static void rtl8169_rx_desc_init(struct rtl8169_private *tp)\n+{\n+\tfor (int i = 0; i \u003c tp-\u003enum_rx_rings; i++) {\n+\t\tstruct rtl8169_rx_ring *ring = \u0026tp-\u003erx_ring[i];\n+\n+\t\tmemset(ring-\u003erx_desc_array, 0x0, R8169_RX_RING_BYTES);\n+\t}\n+}\n+\n static void rtl8169_init_ring_indexes(struct rtl8169_private *tp)\n {\n-\ttp-\u003edirty_tx = tp-\u003ecur_tx = tp-\u003ecur_rx = 0;\n+\ttp-\u003edirty_tx = 0;\n+\ttp-\u003ecur_tx = 0;\n+\n+\tfor (int i = 0; i \u003c tp-\u003enum_rx_rings; i++) {\n+\t\tstruct rtl8169_rx_ring *ring = \u0026tp-\u003erx_ring[i];\n+\n+\t\tring-\u003ecur_rx = 0;\n+\t}\n }\n \n static void rtl_jumbo_config(struct rtl8169_private *tp)\n@@ -2769,6 +2880,29 @@ static void rtl_hw_reset(struct rtl8169_private *tp)\n \trtl_loop_wait_low(tp, \u0026rtl_chipcmd_cond, 100, 100);\n }\n \n+static void rtl8169_init_rss(struct rtl8169_private *tp)\n+{\n+\tfor (int i = 0; i \u003c tp-\u003erss_data-\u003ehw_supp_indir_tbl_entries; i++)\n+\t\ttp-\u003erss_data-\u003erss_indir_tbl[i] = ethtool_rxfh_indir_default(i, tp-\u003enum_rx_rings);\n+\n+\tnetdev_rss_key_fill(tp-\u003erss_data-\u003erss_key, RTL_RSS_KEY_SIZE);\n+}\n+\n+static void rtl_setup_rx_params(struct rtl8169_private *tp)\n+{\n+\ttp-\u003enum_rx_rings = 1;\n+\tswitch (tp-\u003emac_version) {\n+\tcase RTL_GIGA_MAC_VER_80:\n+\t\ttp-\u003ehw_supp_num_rx_queues = R8169_MAX_RX_QUEUES;\n+\t\ttp-\u003erss_data-\u003ehw_supp_indir_tbl_entries = RTL_MAX_INDIRECTION_TABLE_ENTRIES;\n+\t\tbreak;\n+\tdefault:\n+\t\ttp-\u003ehw_supp_num_rx_queues = R8169_DEFAULT_RX_QUEUES;\n+\t\tbreak;\n+\t}\n+\ttp-\u003einit_rx_desc_type = RX_DESC_TYPE_DEFAULT;\n+}\n+\n static void rtl_request_firmware(struct rtl8169_private *tp)\n {\n \tstruct rtl_fw *rtl_fw;\n@@ -2891,8 +3025,62 @@ static void rtl_set_rx_max_size(struct rtl8169_private *tp)\n \tRTL_W16(tp, RxMaxSize, R8169_RX_BUF_SIZE + 1);\n }\n \n+static void rtl8169_store_rss_key(struct rtl8169_private *tp)\n+{\n+\tu8 *rss_key = tp-\u003erss_data-\u003erss_key;\n+\tconst u16 rss_key_reg = RSS_KEY_REG;\n+\n+\t/* Write RSS key to HW */\n+\tfor (int i = 0; i \u003c RTL_RSS_KEY_SIZE; i += sizeof(u32))\n+\t\tRTL_W32(tp, rss_key_reg + i, get_unaligned_le32(rss_key + i));\n+}\n+\n+static void rtl8169_store_reta(struct rtl8169_private *tp)\n+{\n+\tu8 *indir_tbl = tp-\u003erss_data-\u003erss_indir_tbl;\n+\tunsigned int i;\n+\n+\t/* Write redirection table to HW */\n+\tfor (i = 0; i \u003c tp-\u003erss_data-\u003ehw_supp_indir_tbl_entries; i += 4) {\n+\t\tu32 reta = get_unaligned_le32(\u0026indir_tbl[i]);\n+\n+\t\tRTL_W32(tp, RSS_INDIRECTION_TBL_REG + i, reta);\n+\t}\n+}\n+\n+static void rtl8169_set_rss_hash_opt(struct rtl8169_private *tp)\n+{\n+\tu32 rss_ctrl;\n+\n+\trss_ctrl = FIELD_PREP(RSS_CPU_NUM_MASK, ilog2(tp-\u003enum_rx_rings));\n+\n+\t/* Perform hash on these packet types */\n+\trss_ctrl |= RSS_CTRL_TCP_IPV4_SUPP |\n+\t\t RSS_CTRL_IPV4_SUPP |\n+\t\t RSS_CTRL_IPV6_SUPP |\n+\t\t RSS_CTRL_IPV6_EXT_SUPP |\n+\t\t RSS_CTRL_TCP_IPV6_SUPP |\n+\t\t RSS_CTRL_TCP_IPV6_EXT_SUPP |\n+\t\t RSS_CTRL_UDP_IPV4_SUPP |\n+\t\t RSS_CTRL_UDP_IPV6_SUPP;\n+\n+\trss_ctrl |= FIELD_PREP(RSS_HASH_MASK,\n+\t\t\t ilog2(tp-\u003erss_data-\u003ehw_supp_indir_tbl_entries));\n+\n+\tRTL_W32(tp, RSS_CTRL_8125, rss_ctrl);\n+}\n+\n+static void rtl_set_rss_config(struct rtl8169_private *tp)\n+{\n+\trtl8169_set_rss_hash_opt(tp);\n+\trtl8169_store_reta(tp);\n+\trtl8169_store_rss_key(tp);\n+}\n+\n static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp)\n {\n+\tstruct rtl8169_rx_ring *ring = \u0026tp-\u003erx_ring[0];\n+\n \t/*\n \t * Magic spell: some iop3xx ARM board needs the TxDescAddrHigh\n \t * register to be written before TxDescAddrLow to work.\n@@ -2900,8 +3088,18 @@ static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp)\n \t */\n \tRTL_W32(tp, TxDescStartAddrHigh, ((u64) tp-\u003eTxPhyAddr) \u003e\u003e 32);\n \tRTL_W32(tp, TxDescStartAddrLow, ((u64) tp-\u003eTxPhyAddr) \u0026 DMA_BIT_MASK(32));\n-\tRTL_W32(tp, RxDescAddrHigh, ((u64) tp-\u003eRxPhyAddr) \u003e\u003e 32);\n-\tRTL_W32(tp, RxDescAddrLow, ((u64) tp-\u003eRxPhyAddr) \u0026 DMA_BIT_MASK(32));\n+\tRTL_W32(tp, RxDescAddrHigh, ((u64)ring-\u003erx_phy_addr) \u003e\u003e 32);\n+\tRTL_W32(tp, RxDescAddrLow,\n+\t\t((u64)ring-\u003erx_phy_addr) \u0026 DMA_BIT_MASK(32));\n+\n+\tfor (int i = 1; i \u003c tp-\u003enum_rx_rings; i++) {\n+\t\tunsigned int rdsar_reg = RDSAR_Q1_LOW + (i - 1) * 8;\n+\t\tstruct rtl8169_rx_ring *ring = \u0026tp-\u003erx_ring[i];\n+\n+\t\tRTL_W32(tp, rdsar_reg + 4, ((u64)ring-\u003erx_phy_addr \u003e\u003e 32));\n+\t\tRTL_W32(tp, rdsar_reg,\n+\t\t\t((u64)ring-\u003erx_phy_addr) \u0026 DMA_BIT_MASK(32));\n+\t}\n }\n \n static void rtl8169_set_magic_reg(struct rtl8169_private *tp)\n@@ -4012,6 +4210,27 @@ DECLARE_RTL_COND(rtl_mac_ocp_e00e_cond)\n \treturn r8168_mac_ocp_read(tp, 0xe00e) \u0026 BIT(13);\n }\n \n+static void rtl8125_set_rx_q_num(struct rtl8169_private *tp)\n+{\n+\tu16 rx_q_num;\n+\tu16 q_ctrl;\n+\n+\trx_q_num = ilog2(tp-\u003enum_rx_rings);\n+\tq_ctrl = RTL_R16(tp, Q_NUM_CTRL_8125);\n+\tq_ctrl \u0026= ~RTL_RX_Q_NUM_MASK;\n+\tq_ctrl |= FIELD_PREP(RTL_RX_Q_NUM_MASK, rx_q_num);\n+\tRTL_W16(tp, Q_NUM_CTRL_8125, q_ctrl);\n+}\n+\n+static void rtl8169_hw_enable_vec_mapping(struct rtl8169_private *tp)\n+{\n+\tu8 tmp;\n+\n+\ttmp = RTL_R8(tp, INT_CFG0_8125);\n+\ttmp |= INT_CFG0_ENABLE_8125;\n+\tRTL_W8(tp, INT_CFG0_8125, tmp);\n+}\n+\n static void rtl_hw_start_8125_common(struct rtl8169_private *tp)\n {\n \trtl_pcie_state_l2l3_disable(tp);\n@@ -4020,6 +4239,9 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp)\n \tRTL_W32(tp, RSS_CTRL_8125, 0);\n \tRTL_W16(tp, Q_NUM_CTRL_8125, 0);\n \n+\tif (tp-\u003eirq_nvecs \u003e 1)\n+\t\trtl8169_hw_enable_vec_mapping(tp);\n+\n \t/* disable UPS */\n \tr8168_mac_ocp_modify(tp, 0xd40a, 0x0010, 0x0000);\n \n@@ -4039,6 +4261,13 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp)\n \t tp-\u003emac_version == RTL_GIGA_MAC_VER_80)\n \t\tRTL_W8(tp, 0xD8, RTL_R8(tp, 0xD8) \u0026 ~0x02);\n \n+\t/* enable rx descriptor type v4 and set queue num for rss */\n+\tif (tp-\u003enum_rx_rings \u003e 1) {\n+\t\trtl8125_set_rx_q_num(tp);\n+\t\tRTL_W8(tp, RTL_DESC_TYPE_CTRL,\n+\t\t RTL_R8(tp, RTL_DESC_TYPE_CTRL) | RTL_DESC_TYPE_RSS);\n+\t}\n+\n \tif (tp-\u003emac_version == RTL_GIGA_MAC_VER_80)\n \t\tr8168_mac_ocp_modify(tp, 0xe614, 0x0f00, 0x0f00);\n \telse if (tp-\u003emac_version == RTL_GIGA_MAC_VER_70)\n@@ -4275,6 +4504,12 @@ static void rtl_hw_start(struct rtl8169_private *tp)\n \trtl_hw_aspm_clkreq_enable(tp, true);\n \trtl_set_rx_max_size(tp);\n \trtl_set_rx_tx_desc_registers(tp);\n+\tif (rtl_is_8125(tp)) {\n+\t\tif (tp-\u003enum_rx_rings \u003e 1)\n+\t\t\trtl_set_rss_config(tp);\n+\t\telse\n+\t\t\tRTL_W32(tp, RSS_CTRL_8125, 0x00);\n+\t}\n \trtl_lock_config_regs(tp);\n \n \trtl_jumbo_config(tp);\n@@ -4313,19 +4548,32 @@ static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)\n \treturn 0;\n }\n \n-static void rtl8169_mark_to_asic(struct RxDesc *desc)\n+static void rtl8169_mark_to_asic(struct rtl8169_private *tp, struct RxDesc *desc)\n {\n-\tu32 eor = le32_to_cpu(desc-\u003eopts1) \u0026 RingEnd;\n+\tu32 eor;\n \n-\tdesc-\u003eopts2 = 0;\n-\t/* Force memory writes to complete before releasing descriptor */\n-\tdma_wmb();\n-\tWRITE_ONCE(desc-\u003eopts1, cpu_to_le32(DescOwn | eor | R8169_RX_BUF_SIZE));\n+\tswitch (tp-\u003einit_rx_desc_type) {\n+\tcase RX_DESC_TYPE_RSS:\n+\t\teor = le32_to_cpu(desc-\u003erss_opts1) \u0026 RingEnd;\n+\t\tdesc-\u003erss_opts2 = cpu_to_le32(0);\n+\t\t/* Force memory writes to complete before releasing descriptor */\n+\t\tdma_wmb();\n+\t\tWRITE_ONCE(desc-\u003erss_opts1, cpu_to_le32(DescOwn | eor | R8169_RX_BUF_SIZE));\n+\t\tbreak;\n+\tdefault:\n+\t\teor = le32_to_cpu(desc-\u003eopts1) \u0026 RingEnd;\n+\t\tdesc-\u003eopts2 = cpu_to_le32(0);\n+\t\t/* Force memory writes to complete before releasing descriptor */\n+\t\tdma_wmb();\n+\t\tWRITE_ONCE(desc-\u003eopts1, cpu_to_le32(DescOwn | eor | R8169_RX_BUF_SIZE));\n+\t\tbreak;\n+\t}\n }\n \n static struct page *rtl8169_alloc_rx_data(struct rtl8169_private *tp,\n-\t\t\t\t\t struct RxDesc *desc)\n+\t\t\t\t\t struct rtl8169_rx_ring *ring, unsigned int index)\n {\n+\tstruct RxDesc *desc = ring-\u003erx_desc_array + index;\n \tstruct device *d = tp_to_dev(tp);\n \tint node = dev_to_node(d);\n \tdma_addr_t mapping;\n@@ -4342,56 +4590,128 @@ static struct page *rtl8169_alloc_rx_data(struct rtl8169_private *tp,\n \t\treturn NULL;\n \t}\n \n-\tdesc-\u003eaddr = cpu_to_le64(mapping);\n-\trtl8169_mark_to_asic(desc);\n+\tring-\u003erx_desc_phy_addr[index] = mapping;\n+\tif (tp-\u003einit_rx_desc_type == RX_DESC_TYPE_RSS)\n+\t\tdesc-\u003erss_addr = cpu_to_le64(mapping);\n+\telse\n+\t\tdesc-\u003eaddr = cpu_to_le64(mapping);\n+\trtl8169_mark_to_asic(tp, desc);\n \n \treturn data;\n }\n \n-static void rtl8169_rx_clear(struct rtl8169_private *tp)\n+static void rtl8169_rx_clear(struct rtl8169_private *tp,\n+\t\t\t struct rtl8169_rx_ring *ring)\n {\n \tint i;\n \n-\tfor (i = 0; i \u003c NUM_RX_DESC \u0026\u0026 tp-\u003eRx_databuff[i]; i++) {\n+\tfor (i = 0; i \u003c NUM_RX_DESC \u0026\u0026 ring-\u003erx_databuff[i]; i++) {\n \t\tdma_unmap_page(tp_to_dev(tp),\n-\t\t\t le64_to_cpu(tp-\u003eRxDescArray[i].addr),\n+\t\t\t ring-\u003erx_desc_phy_addr[i],\n \t\t\t R8169_RX_BUF_SIZE, DMA_FROM_DEVICE);\n-\t\t__free_pages(tp-\u003eRx_databuff[i], get_order(R8169_RX_BUF_SIZE));\n-\t\ttp-\u003eRx_databuff[i] = NULL;\n-\t\ttp-\u003eRxDescArray[i].addr = 0;\n-\t\ttp-\u003eRxDescArray[i].opts1 = 0;\n+\t\t__free_pages(ring-\u003erx_databuff[i], get_order(R8169_RX_BUF_SIZE));\n+\t\tring-\u003erx_databuff[i] = NULL;\n+\t\tring-\u003erx_desc_phy_addr[i] = 0;\n+\t\tif (tp-\u003einit_rx_desc_type == RX_DESC_TYPE_RSS) {\n+\t\t\tring-\u003erx_desc_array[i].rss_addr = 0;\n+\t\t\tring-\u003erx_desc_array[i].rss_opts1 = 0;\n+\t\t} else {\n+\t\t\tring-\u003erx_desc_array[i].addr = 0;\n+\t\t\tring-\u003erx_desc_array[i].opts1 = 0;\n+\t\t}\n+\t}\n+}\n+\n+static void rtl8169_mark_as_last_descriptor(struct rtl8169_private *tp, struct RxDesc *desc)\n+{\n+\tswitch (tp-\u003einit_rx_desc_type) {\n+\tcase RX_DESC_TYPE_RSS:\n+\t\tdesc-\u003erss_opts1 |= cpu_to_le32(RingEnd);\n+\t\tbreak;\n+\tdefault:\n+\t\tdesc-\u003eopts1 |= cpu_to_le32(RingEnd);\n+\t\tbreak;\n \t}\n }\n \n-static int rtl8169_rx_fill(struct rtl8169_private *tp)\n+static int rtl8169_rx_fill(struct rtl8169_private *tp, struct rtl8169_rx_ring *ring)\n {\n \tint i;\n \n \tfor (i = 0; i \u003c NUM_RX_DESC; i++) {\n \t\tstruct page *data;\n \n-\t\tdata = rtl8169_alloc_rx_data(tp, tp-\u003eRxDescArray + i);\n+\t\tdata = rtl8169_alloc_rx_data(tp, ring, i);\n \t\tif (!data) {\n-\t\t\trtl8169_rx_clear(tp);\n+\t\t\trtl8169_rx_clear(tp, ring);\n \t\t\treturn -ENOMEM;\n \t\t}\n-\t\ttp-\u003eRx_databuff[i] = data;\n+\t\tring-\u003erx_databuff[i] = data;\n \t}\n \n \t/* mark as last descriptor in the ring */\n-\ttp-\u003eRxDescArray[NUM_RX_DESC - 1].opts1 |= cpu_to_le32(RingEnd);\n+\trtl8169_mark_as_last_descriptor(tp, \u0026ring-\u003erx_desc_array[NUM_RX_DESC - 1]);\n \n \treturn 0;\n }\n \n+static int rtl8169_alloc_rx_desc(struct rtl8169_private *tp)\n+{\n+\tstruct pci_dev *pdev = tp-\u003epci_dev;\n+\tstruct rtl8169_rx_ring *ring;\n+\n+\tfor (int i = 0; i \u003c tp-\u003enum_rx_rings; i++) {\n+\t\tring = \u0026tp-\u003erx_ring[i];\n+\t\tring-\u003erx_desc_array = dma_alloc_coherent(\u0026pdev-\u003edev,\n+\t\t\t\t\t\t\t R8169_RX_RING_BYTES,\n+\t\t\t\t\t\t\t \u0026ring-\u003erx_phy_addr,\n+\t\t\t\t\t\t\t GFP_KERNEL);\n+\t\tif (!ring-\u003erx_desc_array)\n+\t\t\treturn -ENOMEM;\n+\t}\n+\treturn 0;\n+}\n+\n+static void rtl8169_free_rx_desc(struct rtl8169_private *tp)\n+{\n+\tstruct pci_dev *pdev = tp-\u003epci_dev;\n+\tstruct rtl8169_rx_ring *ring;\n+\n+\tfor (int i = 0; i \u003c tp-\u003enum_rx_rings; i++) {\n+\t\tring = \u0026tp-\u003erx_ring[i];\n+\t\tif (ring-\u003erx_desc_array) {\n+\t\t\tdma_free_coherent(\u0026pdev-\u003edev,\n+\t\t\t\t\t R8169_RX_RING_BYTES,\n+\t\t\t\t\t ring-\u003erx_desc_array,\n+\t\t\t\t\t ring-\u003erx_phy_addr);\n+\t\t\tring-\u003erx_desc_array = NULL;\n+\t\t}\n+\t}\n+}\n+\n static int rtl8169_init_ring(struct rtl8169_private *tp)\n {\n+\tint i, ret;\n+\n \trtl8169_init_ring_indexes(tp);\n+\trtl8169_rx_desc_init(tp);\n \n \tmemset(tp-\u003etx_skb, 0, sizeof(tp-\u003etx_skb));\n-\tmemset(tp-\u003eRx_databuff, 0, sizeof(tp-\u003eRx_databuff));\n \n-\treturn rtl8169_rx_fill(tp);\n+\tfor (i = 0; i \u003c tp-\u003enum_rx_rings; i++) {\n+\t\tstruct rtl8169_rx_ring *ring = \u0026tp-\u003erx_ring[i];\n+\n+\t\tmemset(ring-\u003erx_databuff, 0, sizeof(ring-\u003erx_databuff));\n+\t\tret = rtl8169_rx_fill(tp, ring);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_clear;\n+\t}\n+\treturn 0;\n+\n+err_clear:\n+\twhile (--i \u003e= 0)\n+\t\trtl8169_rx_clear(tp, \u0026tp-\u003erx_ring[i]);\n+\treturn ret;\n }\n \n static void rtl8169_unmap_tx_skb(struct rtl8169_private *tp, unsigned int entry)\n@@ -4431,9 +4751,31 @@ static void rtl8169_tx_clear(struct rtl8169_private *tp)\n \tnetdev_reset_queue(tp-\u003edev);\n }\n \n+static void rtl8169_napi_disable(struct rtl8169_private *tp)\n+{\n+\tif (tp-\u003eirq_nvecs \u003e 1) {\n+\t\tfor (int i = 0; i \u003c tp-\u003enum_rx_rings; i++)\n+\t\t\tnapi_disable(\u0026tp-\u003ertl8169_napi[i]);\n+\t\tnapi_disable(\u0026tp-\u003ertl8169_napi[R8169_MAX_RX_QUEUES]);\n+\t} else {\n+\t\tnapi_disable(\u0026tp-\u003ertl8169_napi[0]);\n+\t}\n+}\n+\n+static void rtl8169_napi_enable(struct rtl8169_private *tp)\n+{\n+\tif (tp-\u003eirq_nvecs \u003e 1) {\n+\t\tfor (int i = 0; i \u003c tp-\u003enum_rx_rings; i++)\n+\t\t\tnapi_enable(\u0026tp-\u003ertl8169_napi[i]);\n+\t\tnapi_enable(\u0026tp-\u003ertl8169_napi[R8169_MAX_RX_QUEUES]);\n+\t} else {\n+\t\tnapi_enable(\u0026tp-\u003ertl8169_napi[0]);\n+\t}\n+}\n+\n static void rtl8169_cleanup(struct rtl8169_private *tp)\n {\n-\tnapi_disable(\u0026tp-\u003enapi);\n+\trtl8169_napi_disable(tp);\n \n \t/* Give a racing hard_start_xmit a few cycles to complete. */\n \tsynchronize_net();\n@@ -4468,18 +4810,30 @@ static void rtl8169_cleanup(struct rtl8169_private *tp)\n \trtl8169_init_ring_indexes(tp);\n }\n \n-static void rtl_reset_work(struct rtl8169_private *tp)\n+static void rtl8169_rx_desc_reset(struct rtl8169_private *tp)\n {\n-\tint i;\n+\tfor (int i = 0; i \u003c tp-\u003enum_rx_rings; i++) {\n+\t\tstruct rtl8169_rx_ring *ring = \u0026tp-\u003erx_ring[i];\n+\n+\t\tfor (int j = 0; j \u003c NUM_RX_DESC; j++) {\n+\t\t\tdma_addr_t phy_addr = ring-\u003erx_desc_phy_addr[j];\n+\n+\t\t\tif (tp-\u003einit_rx_desc_type == RX_DESC_TYPE_RSS)\n+\t\t\t\tring-\u003erx_desc_array[j].rss_addr = cpu_to_le64(phy_addr);\n+\t\t\trtl8169_mark_to_asic(tp, ring-\u003erx_desc_array + j);\n+\t\t}\n+\t}\n+}\n \n+static void rtl_reset_work(struct rtl8169_private *tp)\n+{\n \tnetif_stop_queue(tp-\u003edev);\n \n \trtl8169_cleanup(tp);\n \n-\tfor (i = 0; i \u003c NUM_RX_DESC; i++)\n-\t\trtl8169_mark_to_asic(tp-\u003eRxDescArray + i);\n+\trtl8169_rx_desc_reset(tp);\n \n-\tnapi_enable(\u0026tp-\u003enapi);\n+\trtl8169_napi_enable(tp);\n \trtl_hw_start(tp);\n }\n \n@@ -4923,30 +5277,115 @@ static inline int rtl8169_fragmented_frame(u32 status)\n \treturn (status \u0026 (FirstFrag | LastFrag)) != (FirstFrag | LastFrag);\n }\n \n-static inline void rtl8169_rx_csum(struct sk_buff *skb, u32 opts1)\n+static void rtl8169_rx_hash(struct rtl8169_private *tp,\n+\t\t\t struct RxDesc *desc,\n+\t\t\t struct sk_buff *skb)\n {\n-\tu32 status = opts1 \u0026 (RxProtoMask | RxCSFailMask);\n+\tu32 rss_header_info;\n+\tu32 hash_val;\n+\n+\tif (!(tp-\u003edev-\u003efeatures \u0026 NETIF_F_RXHASH))\n+\t\treturn;\n+\n+\trss_header_info = le32_to_cpu(desc-\u003erss_dword.rss_info);\n+\n+\tif (!(rss_header_info \u0026 RXS_RSS_L3_TYPE_MASK))\n+\t\treturn;\n+\n+\thash_val = le32_to_cpu(desc-\u003erss_dword.rss_result);\n+\n+\tskb_set_hash(skb, hash_val,\n+\t\t (RXS_RSS_L4_TYPE_MASK \u0026 rss_header_info) ?\n+\t\t PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3);\n+}\n+\n+static void rtl8169_rx_csum(struct rtl8169_private *tp,\n+\t\t\t struct sk_buff *skb,\n+\t\t\t u32 opts1)\n+{\n+\tbool csum_ok = false;\n+\n+\tswitch (tp-\u003einit_rx_desc_type) {\n+\tcase RX_DESC_TYPE_RSS:\n+\t\tif (((opts1 \u0026 RX_TCPT_DESC_RSS) \u0026\u0026 !(opts1 \u0026 RX_TCPF_DESC_RSS)) ||\n+\t\t ((opts1 \u0026 RX_UDPT_DESC_RSS) \u0026\u0026 !(opts1 \u0026 RX_UDPF_DESC_RSS)))\n+\t\t\tcsum_ok = true;\n+\t\tbreak;\n+\tdefault: {\n+\t\tu32 status = opts1 \u0026 (RxProtoMask | RxCSFailMask);\n \n-\tif (status == RxProtoTCP || status == RxProtoUDP)\n+\t\tif (status == RxProtoTCP || status == RxProtoUDP)\n+\t\t\tcsum_ok = true;\n+\t\tbreak;\n+\t}\n+\t}\n+\n+\tif (csum_ok)\n \t\tskb-\u003eip_summed = CHECKSUM_UNNECESSARY;\n \telse\n \t\tskb_checksum_none_assert(skb);\n }\n \n-static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, int budget)\n+static __le32 rtl8169_rx_desc_opts1(struct rtl8169_private *tp, struct RxDesc *desc)\n+{\n+\tswitch (tp-\u003einit_rx_desc_type) {\n+\tcase RX_DESC_TYPE_RSS:\n+\t\treturn READ_ONCE(desc-\u003erss_opts1);\n+\tdefault:\n+\t\treturn READ_ONCE(desc-\u003eopts1);\n+\t}\n+}\n+\n+static bool rtl8169_check_rx_desc_error(struct rtl8169_rx_ring *ring,\n+\t\t\t\t\tstruct rtl8169_private *tp,\n+\t\t\t\t\tu32 status)\n+{\n+\tswitch (tp-\u003einit_rx_desc_type) {\n+\tcase RX_DESC_TYPE_RSS:\n+\t\tif (unlikely(status \u0026 RX_RES_RSS)) {\n+\t\t\tu64_stats_update_begin(\u0026ring-\u003estats.syncp);\n+\n+\t\t\t/* Note: The RTL8127 RSS descriptor layout does not have\n+\t\t\t * an RxRWT (Receive Watchdog Timer / over-length) bit.\n+\t\t\t */\n+\t\t\tif (status \u0026 RXRUNT_RSS)\n+\t\t\t\tring-\u003estats.rx_length_errors++;\n+\t\t\tif (status \u0026 RXCRC_RSS)\n+\t\t\t\tring-\u003estats.rx_crc_errors++;\n+\t\t\tu64_stats_update_end(\u0026ring-\u003estats.syncp);\n+\t\t\treturn true;\n+\t\t}\n+\t\tbreak;\n+\tdefault:\n+\t\tif (unlikely(status \u0026 RxRES)) {\n+\t\t\tu64_stats_update_begin(\u0026ring-\u003estats.syncp);\n+\t\t\tif (status \u0026 (RxRWT | RxRUNT))\n+\t\t\t\tring-\u003estats.rx_length_errors++;\n+\t\t\tif (status \u0026 RxCRC)\n+\t\t\t\tring-\u003estats.rx_crc_errors++;\n+\t\t\tu64_stats_update_end(\u0026ring-\u003estats.syncp);\n+\t\t\treturn true;\n+\t\t}\n+\t}\n+\treturn false;\n+}\n+\n+static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp,\n+\t\t struct rtl8169_rx_ring *ring, int budget,\n+\t\t struct napi_struct *napi)\n {\n \tstruct device *d = tp_to_dev(tp);\n \tint count;\n \n-\tfor (count = 0; count \u003c budget; count++, tp-\u003ecur_rx++) {\n-\t\tunsigned int pkt_size, entry = tp-\u003ecur_rx % NUM_RX_DESC;\n-\t\tstruct RxDesc *desc = tp-\u003eRxDescArray + entry;\n+\tfor (count = 0; count \u003c budget; count++, ring-\u003ecur_rx++) {\n+\t\tunsigned int pkt_size, entry = ring-\u003ecur_rx % NUM_RX_DESC;\n+\t\tstruct RxDesc *desc = ring-\u003erx_desc_array + entry;\n \t\tstruct sk_buff *skb;\n \t\tconst void *rx_buf;\n \t\tdma_addr_t addr;\n \t\tu32 status;\n \n-\t\tstatus = le32_to_cpu(READ_ONCE(desc-\u003eopts1));\n+\t\tstatus = le32_to_cpu(rtl8169_rx_desc_opts1(tp, desc));\n \t\tif (status \u0026 DescOwn)\n \t\t\tbreak;\n \n@@ -4956,23 +5395,31 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, int budget\n \t\t */\n \t\tdma_rmb();\n \n-\t\tif (unlikely(status \u0026 RxRES)) {\n+\t\tif (rtl8169_check_rx_desc_error(ring, tp, status)) {\n \t\t\tif (net_ratelimit())\n \t\t\t\tnetdev_warn(dev, \"Rx ERROR. status = %08x\\n\",\n \t\t\t\t\t status);\n-\t\t\tdev-\u003estats.rx_errors++;\n-\t\t\tif (status \u0026 (RxRWT | RxRUNT))\n-\t\t\t\tdev-\u003estats.rx_length_errors++;\n-\t\t\tif (status \u0026 RxCRC)\n-\t\t\t\tdev-\u003estats.rx_crc_errors++;\n+\t\t\tu64_stats_update_begin(\u0026ring-\u003estats.syncp);\n+\t\t\tring-\u003estats.rx_errors++;\n+\t\t\tu64_stats_update_end(\u0026ring-\u003estats.syncp);\n \n \t\t\tif (!(dev-\u003efeatures \u0026 NETIF_F_RXALL))\n \t\t\t\tgoto release_descriptor;\n-\t\t\telse if (status \u0026 RxRWT || !(status \u0026 (RxRUNT | RxCRC)))\n-\t\t\t\tgoto release_descriptor;\n+\n+\t\t\tif (tp-\u003einit_rx_desc_type == RX_DESC_TYPE_DEFAULT) {\n+\t\t\t\tif (status \u0026 RxRWT || !(status \u0026 (RxRUNT | RxCRC)))\n+\t\t\t\t\tgoto release_descriptor;\n+\t\t\t} else {\n+\t\t\t\tif (!(status \u0026 (RXRUNT_RSS | RXCRC_RSS)))\n+\t\t\t\t\tgoto release_descriptor;\n+\t\t\t}\n \t\t}\n \n \t\tpkt_size = status \u0026 GENMASK(13, 0);\n+\n+\t\tif (unlikely(pkt_size \u003c ETH_HLEN + ETH_FCS_LEN))\n+\t\t\tgoto release_descriptor;\n+\n \t\tif (likely(!(dev-\u003efeatures \u0026 NETIF_F_RXFCS)))\n \t\t\tpkt_size -= ETH_FCS_LEN;\n \n@@ -4980,19 +5427,23 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, int budget\n \t\t * They are seen as a symptom of over-mtu sized frames.\n \t\t */\n \t\tif (unlikely(rtl8169_fragmented_frame(status))) {\n-\t\t\tdev-\u003estats.rx_dropped++;\n-\t\t\tdev-\u003estats.rx_length_errors++;\n+\t\t\tu64_stats_update_begin(\u0026ring-\u003estats.syncp);\n+\t\t\tring-\u003estats.rx_dropped++;\n+\t\t\tring-\u003estats.rx_length_errors++;\n+\t\t\tu64_stats_update_end(\u0026ring-\u003estats.syncp);\n \t\t\tgoto release_descriptor;\n \t\t}\n \n-\t\tskb = napi_alloc_skb(\u0026tp-\u003enapi, pkt_size);\n+\t\tskb = napi_alloc_skb(napi, pkt_size);\n \t\tif (unlikely(!skb)) {\n-\t\t\tdev-\u003estats.rx_dropped++;\n+\t\t\tu64_stats_update_begin(\u0026ring-\u003estats.syncp);\n+\t\t\tring-\u003estats.rx_dropped++;\n+\t\t\tu64_stats_update_end(\u0026ring-\u003estats.syncp);\n \t\t\tgoto release_descriptor;\n \t\t}\n \n-\t\taddr = le64_to_cpu(desc-\u003eaddr);\n-\t\trx_buf = page_address(tp-\u003eRx_databuff[entry]);\n+\t\taddr = ring-\u003erx_desc_phy_addr[entry];\n+\t\trx_buf = page_address(ring-\u003erx_databuff[entry]);\n \n \t\tdma_sync_single_for_cpu(d, addr, pkt_size, DMA_FROM_DEVICE);\n \t\tprefetch(rx_buf);\n@@ -5001,19 +5452,28 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, int budget\n \t\tskb-\u003elen = pkt_size;\n \t\tdma_sync_single_for_device(d, addr, pkt_size, DMA_FROM_DEVICE);\n \n-\t\trtl8169_rx_csum(skb, status);\n+\t\tif (tp-\u003enum_rx_rings \u003e 1) {\n+\t\t\trtl8169_rx_hash(tp, desc, skb);\n+\t\t\tskb_record_rx_queue(skb, ring - tp-\u003erx_ring);\n+\t\t}\n+\t\trtl8169_rx_csum(tp, skb, status);\n \t\tskb-\u003eprotocol = eth_type_trans(skb, dev);\n \n-\t\trtl8169_rx_vlan_tag(desc, skb);\n+\t\trtl8169_rx_vlan_tag(tp, desc, skb);\n \n-\t\tif (skb-\u003epkt_type == PACKET_MULTICAST)\n-\t\t\tdev-\u003estats.multicast++;\n+\t\tif (skb-\u003epkt_type == PACKET_MULTICAST) {\n+\t\t\tu64_stats_update_begin(\u0026ring-\u003estats.syncp);\n+\t\t\tring-\u003estats.multicast++;\n+\t\t\tu64_stats_update_end(\u0026ring-\u003estats.syncp);\n+\t\t}\n \n-\t\tnapi_gro_receive(\u0026tp-\u003enapi, skb);\n+\t\tnapi_gro_receive(napi, skb);\n \n \t\tdev_sw_netstats_rx_add(dev, pkt_size);\n release_descriptor:\n-\t\trtl8169_mark_to_asic(desc);\n+\t\tif (tp-\u003einit_rx_desc_type == RX_DESC_TYPE_RSS)\n+\t\t\tdesc-\u003erss_addr = cpu_to_le64(ring-\u003erx_desc_phy_addr[entry]);\n+\t\trtl8169_mark_to_asic(tp, desc);\n \t}\n \n \treturn count;\n@@ -5021,8 +5481,12 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, int budget\n \n static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)\n {\n-\tstruct rtl8169_private *tp = dev_instance;\n-\tu32 status = rtl_get_events(tp);\n+\tstruct napi_struct *napi = dev_instance;\n+\tstruct rtl8169_private *tp;\n+\tu32 status;\n+\n+\ttp = netdev_priv(napi-\u003edev);\n+\tstatus = rtl_get_events(tp);\n \n \tif ((status \u0026 0xffff) == 0xffff || !(status \u0026 tp-\u003eirq_mask))\n \t\treturn IRQ_NONE;\n@@ -5043,13 +5507,127 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)\n \t}\n \n \trtl_irq_disable(tp);\n-\tnapi_schedule(\u0026tp-\u003enapi);\n+\tnapi_schedule(napi);\n out:\n \trtl_ack_events(tp, status);\n \n \treturn IRQ_HANDLED;\n }\n \n+static void rtl8169_free_one_irq(struct rtl8169_private *tp, int i)\n+{\n+\tstruct pci_dev *pdev = tp-\u003epci_dev;\n+\tstruct napi_struct *napi;\n+\tint irq;\n+\n+\tirq = pci_irq_vector(pdev, i);\n+\tnapi = \u0026tp-\u003ertl8169_napi[i];\n+\n+\tif (tp-\u003eirq_nvecs \u003e 1) {\n+\t\tif (i \u003c= R8169_MAX_RX_QUEUES)\n+\t\t\tfree_irq(irq, napi);\n+\t\telse if (i == MSIX_ID_VEC_MAP_LINKCHG)\n+\t\t\tfree_irq(irq, tp);\n+\t} else {\n+\t\tfree_irq(irq, napi);\n+\t}\n+}\n+\n+static void rtl8169_free_irq(struct rtl8169_private *tp)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i \u003c tp-\u003eirq_nvecs; i++)\n+\t\trtl8169_free_one_irq(tp, i);\n+}\n+\n+static void rtl8169_disable_hw_interrupt_msix(struct rtl8169_private *tp,\n+\t\t\t\t\t int message_id)\n+{\n+\tRTL_W32(tp, IMR_CLEAR_VEC_MAP_REG, BIT(message_id));\n+}\n+\n+static void rtl8169_clear_hw_isr(struct rtl8169_private *tp, int message_id)\n+{\n+\tRTL_W32(tp, ISR_VEC_MAP_REG, BIT(message_id));\n+}\n+\n+static void rtl8169_enable_hw_interrupt_msix(struct rtl8169_private *tp,\n+\t\t\t\t\t int message_id)\n+{\n+\tRTL_W32(tp, IMR_SET_VEC_MAP_REG, BIT(message_id));\n+}\n+\n+static irqreturn_t rtl8169_interrupt_msix(int irq, void *dev_instance)\n+{\n+\tstruct napi_struct *napi = dev_instance;\n+\tstruct net_device *dev = napi-\u003edev;\n+\tstruct rtl8169_private *tp;\n+\tint message_id;\n+\n+\ttp = netdev_priv(dev);\n+\tmessage_id = napi - tp-\u003ertl8169_napi;\n+\n+\trtl8169_disable_hw_interrupt_msix(tp, message_id);\n+\trtl8169_clear_hw_isr(tp, message_id);\n+\n+\tnapi_schedule(napi);\n+\n+\treturn IRQ_HANDLED;\n+}\n+\n+static irqreturn_t rtl8169_interrupt_other(int irq, void *dev_instance)\n+{\n+\tstruct rtl8169_private *tp = dev_instance;\n+\n+\trtl8169_clear_hw_isr(tp, MSIX_ID_VEC_MAP_LINKCHG);\n+\tif (tp-\u003ephydev)\n+\t\tphy_mac_interrupt(tp-\u003ephydev);\n+\telse if (tp-\u003esfp_mode)\n+\t\tphylink_mac_change(tp-\u003ephylink,\n+\t\t\t\t !!(RTL_R8(tp, PHYstatus) \u0026 LinkStatus));\n+\treturn IRQ_HANDLED;\n+}\n+\n+static int rtl8169_request_irq(struct rtl8169_private *tp)\n+{\n+\tstruct pci_dev *pdev = tp-\u003epci_dev;\n+\tstruct net_device *dev = tp-\u003edev;\n+\tstruct napi_struct *napi;\n+\tunsigned long irqflags;\n+\tint i, rc, irq;\n+\n+\tirqflags = pci_dev_msi_enabled(pdev) ? IRQF_NO_THREAD : IRQF_SHARED;\n+\n+\tfor (i = 0; i \u003c tp-\u003eirq_nvecs; i++) {\n+\t\tnapi = \u0026tp-\u003ertl8169_napi[i];\n+\t\tirq = pci_irq_vector(pdev, i);\n+\n+\t\tif (tp-\u003eirq_nvecs \u003e 1) {\n+\t\t\t/* RX: 0~7, TX: 8*/\n+\t\t\tif (i \u003c= R8169_MAX_RX_QUEUES)\n+\t\t\t\trc = request_irq(irq, rtl8169_interrupt_msix,\n+\t\t\t\t\t\t irqflags, dev-\u003ename, napi);\n+\t\t\telse if (i == MSIX_ID_VEC_MAP_LINKCHG)\n+\t\t\t\trc = request_irq(irq, rtl8169_interrupt_other,\n+\t\t\t\t\t\t irqflags, dev-\u003ename, tp);\n+\t\t\telse\n+\t\t\t\tcontinue;\n+\t\t} else {\n+\t\t\trc = request_irq(irq, rtl8169_interrupt,\n+\t\t\t\t\t irqflags, dev-\u003ename, napi);\n+\t\t}\n+\t\tif (rc)\n+\t\t\tgoto free_irq;\n+\t}\n+\treturn 0;\n+\n+free_irq:\n+\twhile (--i \u003e= 0)\n+\t\trtl8169_free_one_irq(tp, i);\n+\treturn rc;\n+}\n+\n static void rtl_task(struct work_struct *work)\n {\n \tstruct rtl8169_private *tp =\n@@ -5084,13 +5662,14 @@ static void rtl_task(struct work_struct *work)\n \n static int rtl8169_poll(struct napi_struct *napi, int budget)\n {\n-\tstruct rtl8169_private *tp = container_of(napi, struct rtl8169_private, napi);\n-\tstruct net_device *dev = tp-\u003edev;\n-\tint work_done;\n+\tstruct rtl8169_private *tp = netdev_priv(napi-\u003edev);\n+\tstruct net_device *dev = napi-\u003edev;\n+\tint work_done = 0;\n \n \trtl_tx(dev, tp, budget);\n \n-\twork_done = rtl_rx(dev, tp, budget);\n+\t/* rtl8169_poll() is used only when there is a single RX ring. */\n+\twork_done = rtl_rx(dev, tp, \u0026tp-\u003erx_ring[0], budget, napi);\n \n \tif (work_done \u003c budget \u0026\u0026 napi_complete_done(napi, work_done))\n \t\trtl_irq_enable(tp);\n@@ -5175,7 +5754,7 @@ static void rtl8169_up(struct rtl8169_private *tp)\n \tif (tp-\u003ephydev)\n \t\trtl8169_init_phy(tp);\n \n-\tnapi_enable(\u0026tp-\u003enapi);\n+\trtl8169_napi_enable(tp);\n \tenable_work(\u0026tp-\u003ewk.work);\n \trtl_reset_work(tp);\n }\n@@ -5190,18 +5769,17 @@ static int rtl8169_close(struct net_device *dev)\n \tphylink_stop(tp-\u003ephylink);\n \tnetif_stop_queue(dev);\n \trtl8169_down(tp);\n-\trtl8169_rx_clear(tp);\n+\tfor (int i = 0; i \u003c tp-\u003enum_rx_rings; i++)\n+\t\trtl8169_rx_clear(tp, \u0026tp-\u003erx_ring[i]);\n \n-\tfree_irq(tp-\u003eirq, tp);\n+\trtl8169_free_irq(tp);\n \n \tphylink_disconnect_phy(tp-\u003ephylink);\n \n-\tdma_free_coherent(\u0026pdev-\u003edev, R8169_RX_RING_BYTES, tp-\u003eRxDescArray,\n-\t\t\t tp-\u003eRxPhyAddr);\n \tdma_free_coherent(\u0026pdev-\u003edev, R8169_TX_RING_BYTES, tp-\u003eTxDescArray,\n \t\t\t tp-\u003eTxPhyAddr);\n \ttp-\u003eTxDescArray = NULL;\n-\ttp-\u003eRxDescArray = NULL;\n+\trtl8169_free_rx_desc(tp);\n \n \tpm_runtime_put_sync(\u0026pdev-\u003edev);\n \n@@ -5213,7 +5791,13 @@ static void rtl8169_netpoll(struct net_device *dev)\n {\n \tstruct rtl8169_private *tp = netdev_priv(dev);\n \n-\trtl8169_interrupt(tp-\u003eirq, tp);\n+\tif (tp-\u003eirq_nvecs \u003e 1) {\n+\t\tfor (int i = 0; i \u003c tp-\u003enum_rx_rings; i++)\n+\t\t\trtl8169_interrupt_msix(0, \u0026tp-\u003ertl8169_napi[i]);\n+\t\trtl8169_interrupt_msix(0, \u0026tp-\u003ertl8169_napi[R8169_MAX_RX_QUEUES]);\n+\t} else {\n+\t\trtl8169_interrupt(0, \u0026tp-\u003ertl8169_napi[0]);\n+\t}\n }\n #endif\n \n@@ -5221,7 +5805,6 @@ static int rtl_open(struct net_device *dev)\n {\n \tstruct rtl8169_private *tp = netdev_priv(dev);\n \tstruct pci_dev *pdev = tp-\u003epci_dev;\n-\tunsigned long irqflags;\n \tint retval = -ENOMEM;\n \n \tpm_runtime_get_sync(\u0026pdev-\u003edev);\n@@ -5235,10 +5818,8 @@ static int rtl_open(struct net_device *dev)\n \tif (!tp-\u003eTxDescArray)\n \t\tgoto out;\n \n-\ttp-\u003eRxDescArray = dma_alloc_coherent(\u0026pdev-\u003edev, R8169_RX_RING_BYTES,\n-\t\t\t\t\t \u0026tp-\u003eRxPhyAddr, GFP_KERNEL);\n-\tif (!tp-\u003eRxDescArray)\n-\t\tgoto err_free_tx_0;\n+\tif (rtl8169_alloc_rx_desc(tp) \u003c 0)\n+\t\tgoto err_free_rx_1;\n \n \tretval = rtl8169_init_ring(tp);\n \tif (retval \u003c 0)\n@@ -5246,8 +5827,7 @@ static int rtl_open(struct net_device *dev)\n \n \trtl_request_firmware(tp);\n \n-\tirqflags = pci_dev_msi_enabled(pdev) ? IRQF_NO_THREAD : IRQF_SHARED;\n-\tretval = request_irq(tp-\u003eirq, rtl8169_interrupt, irqflags, dev-\u003ename, tp);\n+\tretval = rtl8169_request_irq(tp);\n \tif (retval \u003c 0)\n \t\tgoto err_release_fw_2;\n \n@@ -5266,15 +5846,13 @@ static int rtl_open(struct net_device *dev)\n \treturn retval;\n \n err_free_irq:\n-\tfree_irq(tp-\u003eirq, tp);\n+\trtl8169_free_irq(tp);\n err_release_fw_2:\n \trtl_release_firmware(tp);\n-\trtl8169_rx_clear(tp);\n+\tfor (int i = 0; i \u003c tp-\u003enum_rx_rings; i++)\n+\t\trtl8169_rx_clear(tp, \u0026tp-\u003erx_ring[i]);\n err_free_rx_1:\n-\tdma_free_coherent(\u0026pdev-\u003edev, R8169_RX_RING_BYTES, tp-\u003eRxDescArray,\n-\t\t\t tp-\u003eRxPhyAddr);\n-\ttp-\u003eRxDescArray = NULL;\n-err_free_tx_0:\n+\trtl8169_free_rx_desc(tp);\n \tdma_free_coherent(\u0026pdev-\u003edev, R8169_TX_RING_BYTES, tp-\u003eTxDescArray,\n \t\t\t tp-\u003eTxPhyAddr);\n \ttp-\u003eTxDescArray = NULL;\n@@ -5293,6 +5871,27 @@ rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)\n \tnetdev_stats_to_stats64(stats, \u0026dev-\u003estats);\n \tdev_fetch_sw_netstats(stats, dev-\u003etstats);\n \n+\tfor (int i = 0; i \u003c tp-\u003enum_rx_rings; i++) {\n+\t\tu64 errors, dropped, length_errors, crc_errors, multicast;\n+\t\tstruct rtl8169_rx_ring *ring = \u0026tp-\u003erx_ring[i];\n+\t\tunsigned int start;\n+\n+\t\tdo {\n+\t\t\tstart = u64_stats_fetch_begin(\u0026ring-\u003estats.syncp);\n+\t\t\terrors = ring-\u003estats.rx_errors;\n+\t\t\tdropped = ring-\u003estats.rx_dropped;\n+\t\t\tlength_errors = ring-\u003estats.rx_length_errors;\n+\t\t\tcrc_errors = ring-\u003estats.rx_crc_errors;\n+\t\t\tmulticast = ring-\u003estats.multicast;\n+\t\t} while (u64_stats_fetch_retry(\u0026ring-\u003estats.syncp, start));\n+\n+\t\tstats-\u003erx_errors += errors;\n+\t\tstats-\u003erx_dropped += dropped;\n+\t\tstats-\u003erx_length_errors += length_errors;\n+\t\tstats-\u003erx_crc_errors += crc_errors;\n+\t\tstats-\u003emulticast += multicast;\n+\t}\n+\n \t/*\n \t * Fetch additional counter values missing in stats collected by driver\n \t * from tally counters.\n@@ -5419,6 +6018,19 @@ static void rtl_shutdown(struct pci_dev *pdev)\n \t\tpci_prepare_to_sleep(pdev);\n }\n \n+static void r8169_free_napi(struct rtl8169_private *tp)\n+{\n+\tif (tp-\u003eirq_nvecs \u003e 1) {\n+\t\tfor (int i = 0; i \u003c tp-\u003enum_rx_rings; i++)\n+\t\t\tnetif_napi_del(\u0026tp-\u003ertl8169_napi[i]);\n+\t\tnetif_napi_del(\u0026tp-\u003ertl8169_napi[R8169_MAX_RX_QUEUES]);\n+\t} else {\n+\t\tnetif_napi_del(\u0026tp-\u003ertl8169_napi[0]);\n+\t}\n+\n+\tkfree(tp-\u003ertl8169_napi);\n+}\n+\n static void rtl_remove_one(struct pci_dev *pdev)\n {\n \tstruct rtl8169_private *tp = pci_get_drvdata(pdev);\n@@ -5432,6 +6044,8 @@ static void rtl_remove_one(struct pci_dev *pdev)\n \t\tr8169_remove_leds(tp-\u003eleds);\n \n \tunregister_netdev(tp-\u003edev);\n+\tr8169_free_napi(tp);\n+\tkfree(tp-\u003erx_ring);\n \tphylink_destroy(tp-\u003ephylink);\n \n \tif (tp-\u003edash_type != RTL_DASH_NONE)\n@@ -5465,15 +6079,49 @@ static const struct net_device_ops rtl_netdev_ops = {\n \n static void rtl_set_irq_mask(struct rtl8169_private *tp)\n {\n-\ttp-\u003eirq_mask = RxOK | RxErr | TxOK | TxErr | LinkChg;\n+\tif (tp-\u003eirq_nvecs \u003e 1) {\n+\t\ttp-\u003eirq_mask = ISRIMR_LINKCHG | ISRIMR_TOK_Q0;\n+\t\tfor (int i = 0; i \u003c tp-\u003enum_rx_rings; i++)\n+\t\t\ttp-\u003eirq_mask |= ISRIMR_ROK_Q0 \u003c\u003c i;\n+\t} else {\n+\t\ttp-\u003eirq_mask = RxOK | RxErr | TxOK | TxErr | LinkChg;\n \n-\tif (tp-\u003emac_version \u003c= RTL_GIGA_MAC_VER_06)\n-\t\ttp-\u003eirq_mask |= SYSErr | RxFIFOOver;\n+\t\tif (tp-\u003emac_version \u003c= RTL_GIGA_MAC_VER_06)\n+\t\t\ttp-\u003eirq_mask |= SYSErr | RxFIFOOver;\n+\t}\n+}\n+\n+static int get_max_irq_nvecs(struct rtl8169_private *tp)\n+{\n+\tif (tp-\u003emac_version == RTL_GIGA_MAC_VER_80)\n+\t\treturn R8127_MAX_NUM_IRQVEC;\n+\treturn R8169_IRQ_DEFAULT;\n+}\n+\n+static int get_min_irq_nvecs(struct rtl8169_private *tp)\n+{\n+\tif (tp-\u003emac_version == RTL_GIGA_MAC_VER_80)\n+\t\treturn R8127_MIN_NUM_IRQVEC;\n+\treturn R8169_IRQ_DEFAULT;\n+}\n+\n+static void rtl8169_set_rx_ring_num(struct rtl8169_private *tp)\n+{\n+\tif (tp-\u003eirq_nvecs \u003e= get_min_irq_nvecs(tp)) {\n+\t\tunsigned int rss_queue_num = netif_get_num_default_rss_queues();\n+\n+\t\ttp-\u003enum_rx_rings = rounddown_pow_of_two(min(rss_queue_num,\n+\t\t\t\t\t\t\t tp-\u003ehw_supp_num_rx_queues));\n+\t\tif (tp-\u003enum_rx_rings \u003e= 2)\n+\t\t\ttp-\u003einit_rx_desc_type = RX_DESC_TYPE_RSS;\n+\t}\n }\n \n static int rtl_alloc_irq(struct rtl8169_private *tp)\n {\n+\tstruct pci_dev *pdev = tp-\u003epci_dev;\n \tunsigned int flags;\n+\tint nvecs;\n \n \tswitch (tp-\u003emac_version) {\n \tcase RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06:\n@@ -5489,7 +6137,21 @@ static int rtl_alloc_irq(struct rtl8169_private *tp)\n \t\tbreak;\n \t}\n \n-\treturn pci_alloc_irq_vectors(tp-\u003epci_dev, 1, 1, flags);\n+\tnvecs = pci_alloc_irq_vectors(pdev, get_min_irq_nvecs(tp),\n+\t\t\t\t get_max_irq_nvecs(tp), flags);\n+\n+\tif (nvecs \u003c 0) {\n+\t\tdev_info(\u0026pdev-\u003edev, \"Failed to allocate %d MSI-X vectors.\\n\",\n+\t\t\t get_min_irq_nvecs(tp));\n+\t\tnvecs = pci_alloc_irq_vectors(pdev, 1, 1, flags);\n+\t}\n+\n+\tif (nvecs \u003c 0)\n+\t\treturn nvecs;\n+\n+\ttp-\u003eirq_nvecs = nvecs;\n+\n+\treturn 0;\n }\n \n static void rtl_read_mac_address(struct rtl8169_private *tp,\n@@ -6005,6 +6667,117 @@ static int rtl_init_phylink(struct rtl8169_private *tp)\n \treturn 0;\n }\n \n+static int rtl8169_poll_msix_rx(struct napi_struct *napi, int budget)\n+{\n+\tstruct net_device *dev = napi-\u003edev;\n+\tstruct rtl8169_private *tp;\n+\tint work_done = 0;\n+\tint message_id;\n+\n+\ttp = netdev_priv(dev);\n+\tmessage_id = napi - tp-\u003ertl8169_napi;\n+\n+\tif (message_id \u003c tp-\u003enum_rx_rings)\n+\t\twork_done += rtl_rx(dev, tp, \u0026tp-\u003erx_ring[message_id],\n+\t\t\t\t budget, napi);\n+\n+\tif (work_done \u003c budget \u0026\u0026 napi_complete_done(napi, work_done))\n+\t\trtl8169_enable_hw_interrupt_msix(tp, message_id);\n+\n+\treturn work_done;\n+}\n+\n+static int rtl8169_poll_msix_tx(struct napi_struct *napi, int budget)\n+{\n+\tstruct net_device *dev = napi-\u003edev;\n+\tstruct rtl8169_private *tp;\n+\n+\ttp = netdev_priv(dev);\n+\n+\t/* Currently r8169 only supports a single Tx ring.\n+\t * Therefore, we don't need a per-ring Tx processing loop here.\n+\t */\n+\trtl_tx(dev, tp, budget);\n+\n+\tif (budget \u0026\u0026 napi_complete_done(napi, 0))\n+\t\trtl8169_enable_hw_interrupt_msix(tp, (int)(napi - tp-\u003ertl8169_napi));\n+\n+\treturn 0;\n+}\n+\n+/* RTL8127 MSI-X vector layout:\n+ * Vectors 0 .. (MAX_RXQ - 1)\t\t\t: Rx Queues\n+ * Vectors MAX_RXQ .. (MAX_RXQ + MAX_TXQ - 1)\t: Tx Queues\n+ * NAPI is only allocated for data path\n+ */\n+static void r8169_init_napi(struct rtl8169_private *tp)\n+{\n+\tint i;\n+\n+\tif (tp-\u003eirq_nvecs \u003e 1) {\n+\t\tfor (i = 0; i \u003c tp-\u003enum_rx_rings; i++) {\n+\t\t\tnetif_napi_add(tp-\u003edev, \u0026tp-\u003ertl8169_napi[i],\n+\t\t\t\t rtl8169_poll_msix_rx);\n+\t\t\tnetif_napi_set_irq(\u0026tp-\u003ertl8169_napi[i],\n+\t\t\t\t\t pci_irq_vector(tp-\u003epci_dev, i));\n+\t\t}\n+\t\tnetif_napi_add_tx(tp-\u003edev,\n+\t\t\t\t \u0026tp-\u003ertl8169_napi[R8169_MAX_RX_QUEUES],\n+\t\t\t\t rtl8169_poll_msix_tx);\n+\t\tnetif_napi_set_irq(\u0026tp-\u003ertl8169_napi[R8169_MAX_RX_QUEUES],\n+\t\t\t\t pci_irq_vector(tp-\u003epci_dev, R8169_MAX_RX_QUEUES));\n+\t} else {\n+\t\tnetif_napi_add(tp-\u003edev, \u0026tp-\u003ertl8169_napi[0], rtl8169_poll);\n+\t\tnetif_napi_set_irq(\u0026tp-\u003ertl8169_napi[0],\n+\t\t\t\t pci_irq_vector(tp-\u003epci_dev, 0));\n+\t}\n+}\n+\n+static void rtl8169_get_channels(struct net_device *dev,\n+\t\t\t\t struct ethtool_channels *ch)\n+{\n+\tstruct rtl8169_private *tp = netdev_priv(dev);\n+\n+\tif (tp-\u003eirq_nvecs \u003e 1) {\n+\t\tch-\u003emax_rx = tp-\u003ehw_supp_num_rx_queues;\n+\t\tch-\u003emax_tx = 1;\n+\t\tch-\u003erx_count = tp-\u003enum_rx_rings;\n+\t\tch-\u003etx_count = 1;\n+\t} else {\n+\t\tch-\u003emax_combined = 1;\n+\t\tch-\u003ecombined_count = 1;\n+\t}\n+}\n+\n+static const struct ethtool_ops rtl8169_ethtool_ops = {\n+\t.supported_coalesce_params = ETHTOOL_COALESCE_USECS |\n+\t\t\t\t ETHTOOL_COALESCE_MAX_FRAMES,\n+\t.get_drvinfo\t\t= rtl8169_get_drvinfo,\n+\t.get_regs_len\t\t= rtl8169_get_regs_len,\n+\t.get_link\t\t= ethtool_op_get_link,\n+\t.get_coalesce\t\t= rtl_get_coalesce,\n+\t.set_coalesce\t\t= rtl_set_coalesce,\n+\t.get_regs\t\t= rtl8169_get_regs,\n+\t.get_wol\t\t= rtl8169_get_wol,\n+\t.set_wol\t\t= rtl8169_set_wol,\n+\t.get_strings\t\t= rtl8169_get_strings,\n+\t.get_sset_count\t\t= rtl8169_get_sset_count,\n+\t.get_ethtool_stats\t= rtl8169_get_ethtool_stats,\n+\t.get_ts_info\t\t= ethtool_op_get_ts_info,\n+\t.nway_reset\t\t= rtl8169_nway_reset,\n+\t.get_eee\t\t= rtl8169_get_eee,\n+\t.set_eee\t\t= rtl8169_set_eee,\n+\t.get_channels\t\t= rtl8169_get_channels,\n+\t.get_link_ksettings\t= rtl8169_get_link_ksettings,\n+\t.set_link_ksettings\t= rtl8169_set_link_ksettings,\n+\t.get_ringparam\t\t= rtl8169_get_ringparam,\n+\t.get_pause_stats\t= rtl8169_get_pause_stats,\n+\t.get_pauseparam\t\t= rtl8169_get_pauseparam,\n+\t.set_pauseparam\t\t= rtl8169_set_pauseparam,\n+\t.get_eth_mac_stats\t= rtl8169_get_eth_mac_stats,\n+\t.get_eth_ctrl_stats\t= rtl8169_get_eth_ctrl_stats,\n+};\n+\n static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)\n {\n \tconst struct rtl_chip_info *chip;\n@@ -6015,7 +6788,10 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)\n \tu32 txconfig;\n \tu32 xid;\n \n-\tdev = devm_alloc_etherdev(\u0026pdev-\u003edev, sizeof (*tp));\n+\tdev = devm_alloc_etherdev_mqs(\u0026pdev-\u003edev, sizeof(*tp),\n+\t\t\t\t R8169_MAX_TX_QUEUES,\n+\t\t\t\t R8169_MAX_RX_QUEUES);\n+\n \tif (!dev)\n \t\treturn -ENOMEM;\n \n@@ -6091,6 +6867,13 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)\n \ttp-\u003edash_type = rtl_get_dash_type(tp);\n \ttp-\u003edash_enabled = rtl_dash_is_enabled(tp);\n \n+\tif (rtl_hw_support_rss(tp)) {\n+\t\ttp-\u003erss_data = devm_kzalloc(\u0026pdev-\u003edev, sizeof(*tp-\u003erss_data),\n+\t\t\t\t\t GFP_KERNEL);\n+\t\tif (!tp-\u003erss_data)\n+\t\t\treturn -ENOMEM;\n+\t}\n+\n \ttp-\u003ecp_cmd = RTL_R16(tp, CPlusCmd) \u0026 CPCMD_MASK;\n \n \tif (sizeof(dma_addr_t) \u003e 4 \u0026\u0026 tp-\u003emac_version \u003e= RTL_GIGA_MAC_VER_18 \u0026\u0026\n@@ -6105,11 +6888,16 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)\n \n \trtl_hw_reset(tp);\n \n+\trtl_setup_rx_params(tp);\n+\n \trc = rtl_alloc_irq(tp);\n \tif (rc \u003c 0)\n \t\treturn dev_err_probe(\u0026pdev-\u003edev, rc, \"Can't allocate interrupt\\n\");\n \n-\ttp-\u003eirq = pci_irq_vector(pdev, 0);\n+\trtl8169_set_rx_ring_num(tp);\n+\n+\tif (rtl_hw_support_rss(tp))\n+\t\trtl8169_init_rss(tp);\n \n \tINIT_WORK(\u0026tp-\u003ewk.work, rtl_task);\n \tdisable_work(\u0026tp-\u003ewk.work);\n@@ -6118,13 +6906,16 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)\n \n \tdev-\u003eethtool_ops = \u0026rtl8169_ethtool_ops;\n \n-\tnetif_napi_add(dev, \u0026tp-\u003enapi, rtl8169_poll);\n-\n \tdev-\u003ehw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM |\n \t\t\t NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;\n \tdev-\u003evlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;\n \tdev-\u003epriv_flags |= IFF_LIVE_ADDR_CHANGE;\n \n+\tif (rtl_hw_support_rss(tp) \u0026\u0026 tp-\u003enum_rx_rings \u003e 1) {\n+\t\tdev-\u003ehw_features |= NETIF_F_RXHASH;\n+\t\tdev-\u003efeatures |= NETIF_F_RXHASH;\n+\t}\n+\n \t/*\n \t * Pretend we are using VLANs; This bypasses a nasty bug where\n \t * Interrupts stop flowing on high load on 8110SCd controllers.\n@@ -6180,6 +6971,10 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)\n \tif (jumbo_max)\n \t\tdev-\u003emax_mtu = jumbo_max;\n \n+\trc = netif_set_real_num_queues(tp-\u003edev, 1, tp-\u003enum_rx_rings);\n+\tif (rc \u003c 0)\n+\t\treturn dev_err_probe(\u0026pdev-\u003edev, rc, \"set tx/rx num failure\\n\");\n+\n \trtl_set_irq_mask(tp);\n \n \ttp-\u003ecounters = dmam_alloc_coherent (\u0026pdev-\u003edev, sizeof(*tp-\u003ecounters),\n@@ -6202,12 +6997,29 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)\n \t\t}\n \t}\n \n-\trc = register_netdev(dev);\n-\tif (rc) {\n-\t\tphylink_destroy(tp-\u003ephylink);\n-\t\treturn rc;\n+\ttp-\u003erx_ring = kcalloc(tp-\u003enum_rx_rings, sizeof(struct rtl8169_rx_ring),\n+\t\t\t GFP_KERNEL);\n+\tif (!tp-\u003erx_ring) {\n+\t\trc = -ENOMEM;\n+\t\tgoto err_destory_phylink;\n+\t}\n+\n+\tfor (int i = 0; i \u003c tp-\u003enum_rx_rings; i++)\n+\t\tu64_stats_init(\u0026tp-\u003erx_ring[i].stats.syncp);\n+\n+\ttp-\u003ertl8169_napi = kcalloc(tp-\u003eirq_nvecs, sizeof(struct napi_struct),\n+\t\t\t\t GFP_KERNEL);\n+\tif (!tp-\u003ertl8169_napi) {\n+\t\trc = -ENOMEM;\n+\t\tgoto err_free_rx_ring;\n \t}\n \n+\tr8169_init_napi(tp);\n+\n+\trc = register_netdev(dev);\n+\tif (rc)\n+\t\tgoto err_free_napi;\n+\n \tif (IS_ENABLED(CONFIG_R8169_LEDS)) {\n \t\tif (rtl_is_8125(tp))\n \t\t\ttp-\u003eleds = rtl8125_init_leds(dev);\n@@ -6215,8 +7027,9 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)\n \t\t\ttp-\u003eleds = rtl8168_init_leds(dev);\n \t}\n \n-\tnetdev_info(dev, \"%s, %pM, %sXID %x, IRQ %d\\n\",\n-\t\t chip-\u003ename, dev-\u003edev_addr, ext_xid_str, xid, tp-\u003eirq);\n+\tnetdev_info(dev, \"%s, %pM, %sXID %x, IRQ %d (%u total)\\n\",\n+\t\t chip-\u003ename, dev-\u003edev_addr, ext_xid_str, xid,\n+\t\t pci_irq_vector(pdev, 0), tp-\u003eirq_nvecs);\n \n \tif (jumbo_max)\n \t\tnetdev_info(dev, \"jumbo features [frames: %d bytes, tx checksumming: %s]\\n\",\n@@ -6236,6 +7049,14 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)\n \t\tpm_runtime_put_sync(\u0026pdev-\u003edev);\n \n \treturn 0;\n+\n+err_free_napi:\n+\tr8169_free_napi(tp);\n+err_free_rx_ring:\n+\tkfree(tp-\u003erx_ring);\n+err_destory_phylink:\n+\tphylink_destroy(tp-\u003ephylink);\n+\treturn rc;\n }\n \n static struct pci_driver rtl8169_pci_driver = {\n"
} |
| 2/1 | 2026/09/29 07:21 | agent | patch-evaluator |
3mModel:core Args: null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch modifies the Realtek r8169 Ethernet driver (drivers/net/ethernet/realtek/r8169_main.c) to add multi-queue RSS and MSI-X support for RTL8127 PCIe NICs. Realtek r8169/r8125/r8127 devices require physical PCIe hardware that is not emulated in standard QEMU or virtualized fuzzing environments (QEMU only emulates the legacy RTL8139 device handled by 8139cp/8139too). Therefore, the modified driver code is structurally unreachable in standard fuzzing environments.",
"WorthFuzzing": false
}Instruction: You are an expert Linux kernel maintainer and security engineer.
Your job is to review a provided patch series and evaluate whether it warrants fuzzing with syzkaller.
IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on internal assumptions. You must actively use your code access
tools to inspect the actual source code, callers, and surrounding context.
================================================================================
1. CORE TRIAGE PHILOSOPHY
================================================================================
The goal of patch fuzzing is to discover crashes, regressions, exposed latent bugs,
and newly triggered assertions introduced by the patch series.
- REACHABILITY IS THE PRIMARY GATE:
Fuzzing can only discover bugs in code that can actually execute in standard virtualized
environments (GCE or QEMU, utilizing software-emulated devices like USB gadgets, netdev, tun/tap).
If the modified code is structurally unreachable (see Section 2), it MUST NOT be fuzzed,
regardless of whether it adds assertions or complex logic.
- DO NOT BLINDLY TRUST "NO FUNCTIONAL CHANGE" (NFCI) OR "REFACTORING" CLAIMS:
Patch authors routinely label changes as "cleanups", "refactorings", or state
"No functional change intended". Do NOT take these claims at face value.
Code refactorings that rearrange logic, introduce helper functions, or alter state management
in core subsystems frequently introduce subtle semantic shifts or uncover latent kernel bugs.
If reachable executable code is modified or refactored, it MUST be fuzzed.
- NEW OR MODIFIED ASSERTIONS IN REACHABLE CODE MUST BE FUZZED:
When a patch introduces or modifies runtime checks or assertions (e.g., WARN_ON*, VM_WARN_ON*,
BUG_ON*, lockdep_assert*) in reachable code paths, it enforces new or stricter invariants.
Even if the author believes the invariant always holds, fuzzing is essential to verify whether
an unusual sequence of operations can violate it.
================================================================================
2. WHEN TO RETURN WorthFuzzing=false (NEGATIVE CRITERIA)
================================================================================
Return WorthFuzzing=false ONLY IF all modified code falls strictly into one or more of these categories:
- Non-kernel and non-executable changes:
* Modifications to Documentation/, comments, or spelling fixes.
* User-space directories, self-tests, samples, or scripts (e.g., tools/, samples/, scripts/, usr/)
that do not affect the compiled kernel image (vmlinux) or kernel modules.
* Purely decorative logging (e.g., message strings in pr_err, printk, dev_info) or tracepoints
that do not alter control flow or data structures.
* Build system or Kconfig changes that do not alter compiled C logic.
- Structurally unreachable hardware:
* Vendor-specific PCIe switches, SmartNICs, or GPU drivers (e.g., mlxsw, pds_core, qed,
ionic, amdgpu) requiring physical ASIC/PCIe cards not emulated in standard QEMU.
- Unreachable execution paths:
* Driver teardown callbacks (.remove, .shutdown, pci_unregister_driver) executed only during
physical PCI hot-unplug or manual sysfs driver unbinding.
* Code paths exclusive to architectures other than the target architecture.
================================================================================
3. WHEN TO RETURN WorthFuzzing=true (POSITIVE CRITERIA)
================================================================================
Return WorthFuzzing=true whenever the patch touches reachable executable code, including:
- Core Subsystems:
* Any logic modifications in memory management (mm/), synchronization/locking (kernel/locking/),
BPF, scheduler, core networking, VFS, or syscall handling.
- Refactorings and Code Cleanups:
* Any restructuring of reachable data structures, helper abstractions, or algorithm flows.
- Runtime Assertions and Defensive Checks:
* Any introduction or alteration of assertions (WARN_ON*, VM_WARN_ON*, BUG_ON*, etc.) in reachable paths.
- Reachable Drivers and Protocols:
* Drivers accessible via virtual buses (virtio, USB gadget, loopback, netlink, binder, sockets, etc.).
================================================================================
4. EXTRACTING FocusSymbols (PREVENTING DILUTION)
================================================================================
When WorthFuzzing=true, you must extract specific kernel functions into FocusSymbols to guide the fuzzer:
- AVOID UBIQUITOUS LIFECYCLE HOT-PATHS:
Do NOT list generic, ubiquitous functions called by almost every program in the corpus
(including, but not limited to: general memory allocators and deallocators, page fault
and trap handlers, or core synchronization primitives; this is not an exhaustive list).
Listing ubiquitous functions causes the fuzzer to classify thousands of unrelated tests as "focused",
which severely dilutes fuzzing effort away from the actual changes.
- TARGET SPECIFIC FEATURE LOGIC AND ENTRYPOINTS:
List functions that specifically implement the logic being added or altered, or direct API entrypoints
for the subsystem feature under review.
- HANDLING STATIC INLINE FUNCTIONS IN HEADERS (.h):
Compiler-inlined static functions (such as static inlines in mm/*.h or include/linux/*.h) lack
distinct symbol addresses in vmlinux and cannot be targeted directly by symbol coverage filters.
If the changes are primarily in static inline helpers, identify non-static, feature-specific caller
functions in .c files that exercise them (avoiding ubiquitous lifecycle wrappers).
================================================================================
5. IDENTIFYING EnableConfigs
================================================================================
Identify any specific CONFIG_ options required to properly compile and reach the modified code:
- Inspect Kconfig files and #ifdef guards; do not make assumptions.
- Check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed.
- Strip any 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.
Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.
Prompt: Target architecture: amd64
For your convenience, here is the diff of the changes:
commit 02191112044d1fe624bd6629e242a4a9e4a02a7d
Author: syz-cluster <triage@syzkaller.com>
Date: Tue Sep 29 07:21:08 2026 +0000
syz-cluster: applied patch under review
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index 5415ff62a2869..7c27254218cce 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -30,6 +30,7 @@
#include <linux/prefetch.h>
#include <linux/ipv6.h>
#include <linux/unaligned.h>
+#include <linux/u64_stats_sync.h>
#include <net/ip6_checksum.h>
#include <net/netdev_queues.h>
@@ -74,9 +75,26 @@
#define NUM_TX_DESC 256 /* Number of Tx descriptor registers */
#define NUM_RX_DESC 256 /* Number of Rx descriptor registers */
#define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc))
+
#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc))
#define R8169_TX_STOP_THRS (MAX_SKB_FRAGS + 1)
#define R8169_TX_START_THRS (2 * R8169_TX_STOP_THRS)
+#define R8169_MAX_RX_QUEUES 8
+#define R8169_DEFAULT_RX_QUEUES 1
+#define R8169_MAX_TX_QUEUES 1
+#define R8127_MAX_NUM_IRQVEC 32
+#define R8127_MIN_NUM_IRQVEC 30
+#define R8169_IRQ_DEFAULT 1
+#define RTL_RSS_KEY_SIZE 40
+#define RSS_CPU_NUM_MASK GENMASK(18, 16)
+#define RSS_HASH_MASK GENMASK(10, 8)
+#define RTL_MAX_INDIRECTION_TABLE_ENTRIES 128
+#define RXS_RSS_UDP BIT(27)
+#define RXS_RSS_IPV4 BIT(28)
+#define RXS_RSS_IPV6 BIT(29)
+#define RXS_RSS_TCP BIT(30)
+#define RXS_RSS_L3_TYPE_MASK (RXS_RSS_IPV4 | RXS_RSS_IPV6)
+#define RXS_RSS_L4_TYPE_MASK (RXS_RSS_TCP | RXS_RSS_UDP)
#define OCP_STD_PHY_BASE 0xa400
@@ -463,11 +481,16 @@ enum rtl8125_registers {
TxPoll_8125 = 0x90,
LEDSEL3 = 0x96,
MAC0_BKP = 0x19e0,
+ RDSAR_Q1_LOW = 0x4000,
RSS_CTRL_8125 = 0x4500,
Q_NUM_CTRL_8125 = 0x4800,
EEE_TXIDLE_TIMER_8125 = 0x6048,
+ IMR_CLEAR_VEC_MAP_REG = 0x0d00,
+ ISR_VEC_MAP_REG = 0x0d04,
+ IMR_SET_VEC_MAP_REG = 0x0d0c,
};
+#define MSIX_ID_VEC_MAP_LINKCHG 29
#define LEDSEL_MASK_8125 0x23f
#define RX_VLAN_INNER_8125 BIT(22)
@@ -496,6 +519,9 @@ enum rtl_register_content {
RxRUNT = (1 << 20),
RxCRC = (1 << 19),
+ RXRUNT_RSS = (1 << 21),
+ RXCRC_RSS = (1 << 20),
+
/* ChipCmdBits */
StopReq = 0x80,
CmdReset = 0x10,
@@ -598,6 +624,23 @@ enum rtl_register_content {
/* magic enable v2 */
MagicPacket_v2 = (1 << 16), /* Wake up when receives a Magic Packet */
+#define ISRIMR_LINKCHG BIT(29)
+#define ISRIMR_TOK_Q0 BIT(8)
+#define ISRIMR_ROK_Q0 BIT(0)
+#define RTL_DESC_TYPE_CTRL 0xd8
+#define RSS_KEY_REG 0x4600
+#define RSS_INDIRECTION_TBL_REG 0x4700
+#define RSS_CTRL_TCP_IPV4_SUPP BIT(0)
+#define RTL_DESC_TYPE_RSS BIT(1)
+#define RSS_CTRL_IPV4_SUPP BIT(1)
+#define RSS_CTRL_TCP_IPV6_SUPP BIT(2)
+#define RSS_CTRL_IPV6_SUPP BIT(3)
+#define RSS_CTRL_IPV6_EXT_SUPP BIT(4)
+#define RSS_CTRL_TCP_IPV6_EXT_SUPP BIT(5)
+#define RSS_CTRL_UDP_IPV4_SUPP BIT(11)
+#define RSS_CTRL_UDP_IPV6_SUPP BIT(12)
+#define RX_RES_RSS BIT(22)
+#define RTL_RX_Q_NUM_MASK GENMASK(4, 2)
};
enum rtl_desc_bit {
@@ -655,6 +698,11 @@ enum rtl_rx_desc_bit {
#define RxProtoIP (PID1 | PID0)
#define RxProtoMask RxProtoIP
+#define RX_UDPT_DESC_RSS BIT(19)
+#define RX_TCPT_DESC_RSS BIT(18)
+#define RX_UDPF_DESC_RSS BIT(16) /* UDP/IP checksum failed */
+#define RX_TCPF_DESC_RSS BIT(15) /* TCP/IP checksum failed */
+
IPFail = (1 << 16), /* IP checksum failed */
UDPFail = (1 << 15), /* UDP/IP checksum failed */
TCPFail = (1 << 14), /* TCP/IP checksum failed */
@@ -676,9 +724,27 @@ struct TxDesc {
};
struct RxDesc {
- __le32 opts1;
- __le32 opts2;
- __le64 addr;
+ union {
+ /* RX_DESC_TYPE_DEFAULT */
+ struct {
+ __le32 opts1;
+ __le32 opts2;
+ __le64 addr;
+ };
+
+ /* RX_DESC_TYPE_RSS */
+ struct {
+ union {
+ __le64 rss_addr;
+ struct {
+ __le32 rss_info;
+ __le32 rss_result;
+ } rss_dword;
+ };
+ __le32 rss_opts2;
+ __le32 rss_opts1;
+ };
+ };
};
struct ring_info {
@@ -750,34 +816,63 @@ enum rtl_dash_type {
RTL_DASH_25_BP,
};
+enum rx_desc_type {
+ RX_DESC_TYPE_DEFAULT,
+ RX_DESC_TYPE_RSS,
+};
+
+struct rtl8169_rx_ring {
+ u32 cur_rx;
+ struct RxDesc *rx_desc_array;
+ dma_addr_t rx_desc_phy_addr[NUM_RX_DESC];
+ dma_addr_t rx_phy_addr;
+ struct page *rx_databuff[NUM_RX_DESC];
+
+ struct {
+ u64 rx_errors;
+ u64 rx_dropped;
+ u64 rx_length_errors;
+ u64 rx_crc_errors;
+ u64 multicast;
+ struct u64_stats_sync syncp;
+ } stats;
+};
+
enum rtl_sfp_mode {
RTL_SFP_NONE,
RTL_SFP_8168_AF,
RTL_SFP_8127_ATF,
};
+struct rtl8169_rss_data {
+ u8 rss_key[RTL_RSS_KEY_SIZE];
+ u8 rss_indir_tbl[RTL_MAX_INDIRECTION_TABLE_ENTRIES];
+ unsigned int hw_supp_indir_tbl_entries;
+};
+
struct rtl8169_private {
void __iomem *mmio_addr; /* memory map physical address */
struct pci_dev *pci_dev;
struct net_device *dev;
struct phy_device *phydev;
- struct napi_struct napi;
enum mac_version mac_version;
enum rtl_dash_type dash_type;
enum rtl_sfp_mode sfp_mode;
- u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
u32 dirty_tx;
struct TxDesc *TxDescArray; /* 256-aligned Tx descriptor ring */
- struct RxDesc *RxDescArray; /* 256-aligned Rx descriptor ring */
dma_addr_t TxPhyAddr;
- dma_addr_t RxPhyAddr;
- struct page *Rx_databuff[NUM_RX_DESC]; /* Rx data buffers */
struct ring_info tx_skb[NUM_TX_DESC]; /* Tx data buffers */
+ struct napi_struct *rtl8169_napi;
+ struct rtl8169_rx_ring *rx_ring;
+ unsigned int num_rx_rings;
u16 cp_cmd;
u16 tx_lpi_timer;
u32 irq_mask;
- int irq;
+ unsigned int hw_supp_num_rx_queues;
+ struct rtl8169_rss_data *rss_data;
+ unsigned int irq_nvecs;
+ enum rx_desc_type init_rx_desc_type;
struct clk *clk;
int speed;
@@ -1692,6 +1787,11 @@ static enum rtl_sfp_mode rtl_get_sfp_mode(struct rtl8169_private *tp)
return RTL_SFP_NONE;
}
+static bool rtl_hw_support_rss(struct rtl8169_private *tp)
+{
+ return tp->mac_version == RTL_GIGA_MAC_VER_80;
+}
+
static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private *tp)
{
switch (tp->mac_version) {
@@ -1758,26 +1858,38 @@ static u32 rtl_get_events(struct rtl8169_private *tp)
static void rtl_ack_events(struct rtl8169_private *tp, u32 bits)
{
- if (rtl_is_8125(tp))
- RTL_W32(tp, IntrStatus_8125, bits);
- else
+ if (rtl_is_8125(tp)) {
+ if (tp->irq_nvecs > 1)
+ RTL_W32(tp, ISR_VEC_MAP_REG, bits);
+ else
+ RTL_W32(tp, IntrStatus_8125, bits);
+ } else {
RTL_W16(tp, IntrStatus, bits);
+ }
}
static void rtl_irq_disable(struct rtl8169_private *tp)
{
- if (rtl_is_8125(tp))
- RTL_W32(tp, IntrMask_8125, 0);
- else
+ if (rtl_is_8125(tp)) {
+ if (tp->irq_nvecs > 1)
+ RTL_W32(tp, IMR_CLEAR_VEC_MAP_REG, 0xffffffff);
+ else
+ RTL_W32(tp, IntrMask_8125, 0);
+ } else {
RTL_W16(tp, IntrMask, 0);
+ }
}
static void rtl_irq_enable(struct rtl8169_private *tp)
{
- if (rtl_is_8125(tp))
- RTL_W32(tp, IntrMask_8125, tp->irq_mask);
- else
+ if (rtl_is_8125(tp)) {
+ if (tp->irq_nvecs > 1)
+ RTL_W32(tp, IMR_SET_VEC_MAP_REG, tp->irq_mask);
+ else
+ RTL_W32(tp, IntrMask_8125, tp->irq_mask);
+ } else {
RTL_W16(tp, IntrMask, tp->irq_mask);
+ }
}
static void rtl8169_irq_mask_and_ack(struct rtl8169_private *tp)
@@ -1979,9 +2091,20 @@ static inline u32 rtl8169_tx_vlan_tag(struct sk_buff *skb)
TxVlanTag | swab16(skb_vlan_tag_get(skb)) : 0x00;
}
-static void rtl8169_rx_vlan_tag(struct RxDesc *desc, struct sk_buff *skb)
+static void rtl8169_rx_vlan_tag(struct rtl8169_private *tp,
+ struct RxDesc *desc,
+ struct sk_buff *skb)
{
- u32 opts2 = le32_to_cpu(desc->opts2);
+ u32 opts2;
+
+ switch (tp->init_rx_desc_type) {
+ case RX_DESC_TYPE_RSS:
+ opts2 = le32_to_cpu(desc->rss_opts2);
+ break;
+ default:
+ opts2 = le32_to_cpu(desc->opts2);
+ break;
+ }
if (opts2 & RxVlanTag)
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), swab16(opts2 & 0xffff));
@@ -2514,34 +2637,6 @@ static int rtl8169_nway_reset(struct net_device *dev)
return phylink_ethtool_nway_reset(tp->phylink);
}
-static const struct ethtool_ops rtl8169_ethtool_ops = {
- .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
- ETHTOOL_COALESCE_MAX_FRAMES,
- .get_drvinfo = rtl8169_get_drvinfo,
- .get_regs_len = rtl8169_get_regs_len,
- .get_link = ethtool_op_get_link,
- .get_coalesce = rtl_get_coalesce,
- .set_coalesce = rtl_set_coalesce,
- .get_regs = rtl8169_get_regs,
- .get_wol = rtl8169_get_wol,
- .set_wol = rtl8169_set_wol,
- .get_strings = rtl8169_get_strings,
- .get_sset_count = rtl8169_get_sset_count,
- .get_ethtool_stats = rtl8169_get_ethtool_stats,
- .get_ts_info = ethtool_op_get_ts_info,
- .nway_reset = rtl8169_nway_reset,
- .get_eee = rtl8169_get_eee,
- .set_eee = rtl8169_set_eee,
- .get_link_ksettings = rtl8169_get_link_ksettings,
- .set_link_ksettings = rtl8169_set_link_ksettings,
- .get_ringparam = rtl8169_get_ringparam,
- .get_pause_stats = rtl8169_get_pause_stats,
- .get_pauseparam = rtl8169_get_pauseparam,
- .set_pauseparam = rtl8169_set_pauseparam,
- .get_eth_mac_stats = rtl8169_get_eth_mac_stats,
- .get_eth_ctrl_stats = rtl8169_get_eth_ctrl_stats,
-};
-
static const struct rtl_chip_info *rtl8169_get_chip_version(u32 xid, bool gmii)
{
/* Chips combining a 1Gbps MAC with a 100Mbps PHY */
@@ -2717,9 +2812,25 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp)
}
}
+static void rtl8169_rx_desc_init(struct rtl8169_private *tp)
+{
+ for (int i = 0; i < tp->num_rx_rings; i++) {
+ struct rtl8169_rx_ring *ring = &tp->rx_ring[i];
+
+ memset(ring->rx_desc_array, 0x0, R8169_RX_RING_BYTES);
+ }
+}
+
static void rtl8169_init_ring_indexes(struct rtl8169_private *tp)
{
- tp->dirty_tx = tp->cur_tx = tp->cur_rx = 0;
+ tp->dirty_tx = 0;
+ tp->cur_tx = 0;
+
+ for (int i = 0; i < tp->num_rx_rings; i++) {
+ struct rtl8169_rx_ring *ring = &tp->rx_ring[i];
+
+ ring->cur_rx = 0;
+ }
}
static void rtl_jumbo_config(struct rtl8169_private *tp)
@@ -2769,6 +2880,29 @@ static void rtl_hw_reset(struct rtl8169_private *tp)
rtl_loop_wait_low(tp, &rtl_chipcmd_cond, 100, 100);
}
+static void rtl8169_init_rss(struct rtl8169_private *tp)
+{
+ for (int i = 0; i < tp->rss_data->hw_supp_indir_tbl_entries; i++)
+ tp->rss_data->rss_indir_tbl[i] = ethtool_rxfh_indir_default(i, tp->num_rx_rings);
+
+ netdev_rss_key_fill(tp->rss_data->rss_key, RTL_RSS_KEY_SIZE);
+}
+
+static void rtl_setup_rx_params(struct rtl8169_private *tp)
+{
+ tp->num_rx_rings = 1;
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_80:
+ tp->hw_supp_num_rx_queues = R8169_MAX_RX_QUEUES;
+ tp->rss_data->hw_supp_indir_tbl_entries = RTL_MAX_INDIRECTION_TABLE_ENTRIES;
+ break;
+ default:
+ tp->hw_supp_num_rx_queues = R8169_DEFAULT_RX_QUEUES;
+ break;
+ }
+ tp->init_rx_desc_type = RX_DESC_TYPE_DEFAULT;
+}
+
static void rtl_request_firmware(struct rtl8169_private *tp)
{
struct rtl_fw *rtl_fw;
@@ -2891,8 +3025,62 @@ static void rtl_set_rx_max_size(struct rtl8169_private *tp)
RTL_W16(tp, RxMaxSize, R8169_RX_BUF_SIZE + 1);
}
+static void rtl8169_store_rss_key(struct rtl8169_private *tp)
+{
+ u8 *rss_key = tp->rss_data->rss_key;
+ const u16 rss_key_reg = RSS_KEY_REG;
+
+ /* Write RSS key to HW */
+ for (int i = 0; i < RTL_RSS_KEY_SIZE; i += sizeof(u32))
+ RTL_W32(tp, rss_key_reg + i, get_unaligned_le32(rss_key + i));
+}
+
+static void rtl8169_store_reta(struct rtl8169_private *tp)
+{
+ u8 *indir_tbl = tp->rss_data->rss_indir_tbl;
+ unsigned int i;
+
+ /* Write redirection table to HW */
+ for (i = 0; i < tp->rss_data->hw_supp_indir_tbl_entries; i += 4) {
+ u32 reta = get_unaligned_le32(&indir_tbl[i]);
+
+ RTL_W32(tp, RSS_INDIRECTION_TBL_REG + i, reta);
+ }
+}
+
+static void rtl8169_set_rss_hash_opt(struct rtl8169_private *tp)
+{
+ u32 rss_ctrl;
+
+ rss_ctrl = FIELD_PREP(RSS_CPU_NUM_MASK, ilog2(tp->num_rx_rings));
+
+ /* Perform hash on these packet types */
+ rss_ctrl |= RSS_CTRL_TCP_IPV4_SUPP |
+ RSS_CTRL_IPV4_SUPP |
+ RSS_CTRL_IPV6_SUPP |
+ RSS_CTRL_IPV6_EXT_SUPP |
+ RSS_CTRL_TCP_IPV6_SUPP |
+ RSS_CTRL_TCP_IPV6_EXT_SUPP |
+ RSS_CTRL_UDP_IPV4_SUPP |
+ RSS_CTRL_UDP_IPV6_SUPP;
+
+ rss_ctrl |= FIELD_PREP(RSS_HASH_MASK,
+ ilog2(tp->rss_data->hw_supp_indir_tbl_entries));
+
+ RTL_W32(tp, RSS_CTRL_8125, rss_ctrl);
+}
+
+static void rtl_set_rss_config(struct rtl8169_private *tp)
+{
+ rtl8169_set_rss_hash_opt(tp);
+ rtl8169_store_reta(tp);
+ rtl8169_store_rss_key(tp);
+}
+
static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp)
{
+ struct rtl8169_rx_ring *ring = &tp->rx_ring[0];
+
/*
* Magic spell: some iop3xx ARM board needs the TxDescAddrHigh
* register to be written before TxDescAddrLow to work.
@@ -2900,8 +3088,18 @@ static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp)
*/
RTL_W32(tp, TxDescStartAddrHigh, ((u64) tp->TxPhyAddr) >> 32);
RTL_W32(tp, TxDescStartAddrLow, ((u64) tp->TxPhyAddr) & DMA_BIT_MASK(32));
- RTL_W32(tp, RxDescAddrHigh, ((u64) tp->RxPhyAddr) >> 32);
- RTL_W32(tp, RxDescAddrLow, ((u64) tp->RxPhyAddr) & DMA_BIT_MASK(32));
+ RTL_W32(tp, RxDescAddrHigh, ((u64)ring->rx_phy_addr) >> 32);
+ RTL_W32(tp, RxDescAddrLow,
+ ((u64)ring->rx_phy_addr) & DMA_BIT_MASK(32));
+
+ for (int i = 1; i < tp->num_rx_rings; i++) {
+ unsigned int rdsar_reg = RDSAR_Q1_LOW + (i - 1) * 8;
+ struct rtl8169_rx_ring *ring = &tp->rx_ring[i];
+
+ RTL_W32(tp, rdsar_reg + 4, ((u64)ring->rx_phy_addr >> 32));
+ RTL_W32(tp, rdsar_reg,
+ ((u64)ring->rx_phy_addr) & DMA_BIT_MASK(32));
+ }
}
static void rtl8169_set_magic_reg(struct rtl8169_private *tp)
@@ -4012,6 +4210,27 @@ DECLARE_RTL_COND(rtl_mac_ocp_e00e_cond)
return r8168_mac_ocp_read(tp, 0xe00e) & BIT(13);
}
+static void rtl8125_set_rx_q_num(struct rtl8169_private *tp)
+{
+ u16 rx_q_num;
+ u16 q_ctrl;
+
+ rx_q_num = ilog2(tp->num_rx_rings);
+ q_ctrl = RTL_R16(tp, Q_NUM_CTRL_8125);
+ q_ctrl &= ~RTL_RX_Q_NUM_MASK;
+ q_ctrl |= FIELD_PREP(RTL_RX_Q_NUM_MASK, rx_q_num);
+ RTL_W16(tp, Q_NUM_CTRL_8125, q_ctrl);
+}
+
+static void rtl8169_hw_enable_vec_mapping(struct rtl8169_private *tp)
+{
+ u8 tmp;
+
+ tmp = RTL_R8(tp, INT_CFG0_8125);
+ tmp |= INT_CFG0_ENABLE_8125;
+ RTL_W8(tp, INT_CFG0_8125, tmp);
+}
+
static void rtl_hw_start_8125_common(struct rtl8169_private *tp)
{
rtl_pcie_state_l2l3_disable(tp);
@@ -4020,6 +4239,9 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp)
RTL_W32(tp, RSS_CTRL_8125, 0);
RTL_W16(tp, Q_NUM_CTRL_8125, 0);
+ if (tp->irq_nvecs > 1)
+ rtl8169_hw_enable_vec_mapping(tp);
+
/* disable UPS */
r8168_mac_ocp_modify(tp, 0xd40a, 0x0010, 0x0000);
@@ -4039,6 +4261,13 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp)
tp->mac_version == RTL_GIGA_MAC_VER_80)
RTL_W8(tp, 0xD8, RTL_R8(tp, 0xD8) & ~0x02);
+ /* enable rx descriptor type v4 and set queue num for rss */
+ if (tp->num_rx_rings > 1) {
+ rtl8125_set_rx_q_num(tp);
+ RTL_W8(tp, RTL_DESC_TYPE_CTRL,
+ RTL_R8(tp, RTL_DESC_TYPE_CTRL) | RTL_DESC_TYPE_RSS);
+ }
+
if (tp->mac_version == RTL_GIGA_MAC_VER_80)
r8168_mac_ocp_modify(tp, 0xe614, 0x0f00, 0x0f00);
else if (tp->mac_version == RTL_GIGA_MAC_VER_70)
@@ -4275,6 +4504,12 @@ static void rtl_hw_start(struct rtl8169_private *tp)
rtl_hw_aspm_clkreq_enable(tp, true);
rtl_set_rx_max_size(tp);
rtl_set_rx_tx_desc_registers(tp);
+ if (rtl_is_8125(tp)) {
+ if (tp->num_rx_rings > 1)
+ rtl_set_rss_config(tp);
+ else
+ RTL_W32(tp, RSS_CTRL_8125, 0x00);
+ }
rtl_lock_config_regs(tp);
rtl_jumbo_config(tp);
@@ -4313,19 +4548,32 @@ static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
-static void rtl8169_mark_to_asic(struct RxDesc *desc)
+static void rtl8169_mark_to_asic(struct rtl8169_private *tp, struct RxDesc *desc)
{
- u32 eor = le32_to_cpu(desc->opts1) & RingEnd;
+ u32 eor;
- desc->opts2 = 0;
- /* Force memory writes to complete before releasing descriptor */
- dma_wmb();
- WRITE_ONCE(desc->opts1, cpu_to_le32(DescOwn | eor | R8169_RX_BUF_SIZE));
+ switch (tp->init_rx_desc_type) {
+ case RX_DESC_TYPE_RSS:
+ eor = le32_to_cpu(desc->rss_opts1) & RingEnd;
+ desc->rss_opts2 = cpu_to_le32(0);
+ /* Force memory writes to complete before releasing descriptor */
+ dma_wmb();
+ WRITE_ONCE(desc->rss_opts1, cpu_to_le32(DescOwn | eor | R8169_RX_BUF_SIZE));
+ break;
+ default:
+ eor = le32_to_cpu(desc->opts1) & RingEnd;
+ desc->opts2 = cpu_to_le32(0);
+ /* Force memory writes to complete before releasing descriptor */
+ dma_wmb();
+ WRITE_ONCE(desc->opts1, cpu_to_le32(DescOwn | eor | R8169_RX_BUF_SIZE));
+ break;
+ }
}
static struct page *rtl8169_alloc_rx_data(struct rtl8169_private *tp,
- struct RxDesc *desc)
+ struct rtl8169_rx_ring *ring, unsigned int index)
{
+ struct RxDesc *desc = ring->rx_desc_array + index;
struct device *d = tp_to_dev(tp);
int node = dev_to_node(d);
dma_addr_t mapping;
@@ -4342,56 +4590,128 @@ static struct page *rtl8169_alloc_rx_data(struct rtl8169_private *tp,
return NULL;
}
- desc->addr = cpu_to_le64(mapping);
- rtl8169_mark_to_asic(desc);
+ ring->rx_desc_phy_addr[index] = mapping;
+ if (tp->init_rx_desc_type == RX_DESC_TYPE_RSS)
+ desc->rss_addr = cpu_to_le64(mapping);
+ else
+ desc->addr = cpu_to_le64(mapping);
+ rtl8169_mark_to_asic(tp, desc);
return data;
}
-static void rtl8169_rx_clear(struct rtl8169_private *tp)
+static void rtl8169_rx_clear(struct rtl8169_private *tp,
+ struct rtl8169_rx_ring *ring)
{
int i;
- for (i = 0; i < NUM_RX_DESC && tp->Rx_databuff[i]; i++) {
+ for (i = 0; i < NUM_RX_DESC && ring->rx_databuff[i]; i++) {
dma_unmap_page(tp_to_dev(tp),
- le64_to_cpu(tp->RxDescArray[i].addr),
+ ring->rx_desc_phy_addr[i],
R8169_RX_BUF_SIZE, DMA_FROM_DEVICE);
- __free_pages(tp->Rx_databuff[i], get_order(R8169_RX_BUF_SIZE));
- tp->Rx_databuff[i] = NULL;
- tp->RxDescArray[i].addr = 0;
- tp->RxDescArray[i].opts1 = 0;
+ __free_pages(ring->rx_databuff[i], get_order(R8169_RX_BUF_SIZE));
+ ring->rx_databuff[i] = NULL;
+ ring->rx_desc_phy_addr[i] = 0;
+ if (tp->init_rx_desc_type == RX_DESC_TYPE_RSS) {
+ ring->rx_desc_array[i].rss_addr = 0;
+ ring->rx_desc_array[i].rss_opts1 = 0;
+ } else {
+ ring->rx_desc_array[i].addr = 0;
+ ring->rx_desc_array[i].opts1 = 0;
+ }
+ }
+}
+
+static void rtl8169_mark_as_last_descriptor(struct rtl8169_private *tp, struct RxDesc *desc)
+{
+ switch (tp->init_rx_desc_type) {
+ case RX_DESC_TYPE_RSS:
+ desc->rss_opts1 |= cpu_to_le32(RingEnd);
+ break;
+ default:
+ desc->opts1 |= cpu_to_le32(RingEnd);
+ break;
}
}
-static int rtl8169_rx_fill(struct rtl8169_private *tp)
+static int rtl8169_rx_fill(struct rtl8169_private *tp, struct rtl8169_rx_ring *ring)
{
int i;
for (i = 0; i < NUM_RX_DESC; i++) {
struct page *data;
- data = rtl8169_alloc_rx_data(tp, tp->RxDescArray + i);
+ data = rtl8169_alloc_rx_data(tp, ring, i);
if (!data) {
- rtl8169_rx_clear(tp);
+ rtl8169_rx_clear(tp, ring);
return -ENOMEM;
}
- tp->Rx_databuff[i] = data;
+ ring->rx_databuff[i] = data;
}
/* mark as last descriptor in the ring */
- tp->RxDescArray[NUM_RX_DESC - 1].opts1 |= cpu_to_le32(RingEnd);
+ rtl8169_mark_as_last_descriptor(tp, &ring->rx_desc_array[NUM_RX_DESC - 1]);
return 0;
}
+static int rtl8169_alloc_rx_desc(struct rtl8169_private *tp)
+{
+ struct pci_dev *pdev = tp->pci_dev;
+ struct rtl8169_rx_ring *ring;
+
+ for (int i = 0; i < tp->num_rx_rings; i++) {
+ ring = &tp->rx_ring[i];
+ ring->rx_desc_array = dma_alloc_coherent(&pdev->dev,
+ R8169_RX_RING_BYTES,
+ &ring->rx_phy_addr,
+ GFP_KERNEL);
+ if (!ring->rx_desc_array)
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static void rtl8169_free_rx_desc(struct rtl8169_private *tp)
+{
+ struct pci_dev *pdev = tp->pci_dev;
+ struct rtl8169_rx_ring *ring;
+
+ for (int i = 0; i < tp->num_rx_rings; i++) {
+ ring = &tp->rx_ring[i];
+ if (ring->rx_desc_array) {
+ dma_free_coherent(&pdev->dev,
+ R8169_RX_RING_BYTES,
+ ring->rx_desc_array,
+ ring->rx_phy_addr);
+ ring->rx_desc_array = NULL;
+ }
+ }
+}
+
static int rtl8169_init_ring(struct rtl8169_private *tp)
{
+ int i, ret;
+
rtl8169_init_ring_indexes(tp);
+ rtl8169_rx_desc_init(tp);
memset(tp->tx_skb, 0, sizeof(tp->tx_skb));
- memset(tp->Rx_databuff, 0, sizeof(tp->Rx_databuff));
- return rtl8169_rx_fill(tp);
+ for (i = 0; i < tp->num_rx_rings; i++) {
+ struct rtl8169_rx_ring *ring = &tp->rx_ring[i];
+
+ memset(ring->rx_databuff, 0, sizeof(ring->rx_databuff));
+ ret = rtl8169_rx_fill(tp, ring);
+ if (ret < 0)
+ goto err_clear;
+ }
+ return 0;
+
+err_clear:
+ while (--i >= 0)
+ rtl8169_rx_clear(tp, &tp->rx_ring[i]);
+ return ret;
}
static void rtl8169_unmap_tx_skb(struct rtl8169_private *tp, unsigned int entry)
@@ -4431,9 +4751,31 @@ static void rtl8169_tx_clear(struct rtl8169_private *tp)
netdev_reset_queue(tp->dev);
}
+static void rtl8169_napi_disable(struct rtl8169_private *tp)
+{
+ if (tp->irq_nvecs > 1) {
+ for (int i = 0; i < tp->num_rx_rings; i++)
+ napi_disable(&tp->rtl8169_napi[i]);
+ napi_disable(&tp->rtl8169_napi[R8169_MAX_RX_QUEUES]);
+ } else {
+ napi_disable(&tp->rtl8169_napi[0]);
+ }
+}
+
+static void rtl8169_napi_enable(struct rtl8169_private *tp)
+{
+ if (tp->irq_nvecs > 1) {
+ for (int i = 0; i < tp->num_rx_rings; i++)
+ napi_enable(&tp->rtl8169_napi[i]);
+ napi_enable(&tp->rtl8169_napi[R8169_MAX_RX_QUEUES]);
+ } else {
+ napi_enable(&tp->rtl8169_napi[0]);
+ }
+}
+
static void rtl8169_cleanup(struct rtl8169_private *tp)
{
- napi_disable(&tp->napi);
+ rtl8169_napi_disable(tp);
/* Give a racing hard_start_xmit a few cycles to complete. */
synchronize_net();
@@ -4468,18 +4810,30 @@ static void rtl8169_cleanup(struct rtl8169_private *tp)
rtl8169_init_ring_indexes(tp);
}
-static void rtl_reset_work(struct rtl8169_private *tp)
+static void rtl8169_rx_desc_reset(struct rtl8169_private *tp)
{
- int i;
+ for (int i = 0; i < tp->num_rx_rings; i++) {
+ struct rtl8169_rx_ring *ring = &tp->rx_ring[i];
+
+ for (int j = 0; j < NUM_RX_DESC; j++) {
+ dma_addr_t phy_addr = ring->rx_desc_phy_addr[j];
+
+ if (tp->init_rx_desc_type == RX_DESC_TYPE_RSS)
+ ring->rx_desc_array[j].rss_addr = cpu_to_le64(phy_addr);
+ rtl8169_mark_to_asic(tp, ring->rx_desc_array + j);
+ }
+ }
+}
+static void rtl_reset_work(struct rtl8169_private *tp)
+{
netif_stop_queue(tp->dev);
rtl8169_cleanup(tp);
- for (i = 0; i < NUM_RX_DESC; i++)
- rtl8169_mark_to_asic(tp->RxDescArray + i);
+ rtl8169_rx_desc_reset(tp);
- napi_enable(&tp->napi);
+ rtl8169_napi_enable(tp);
rtl_hw_start(tp);
}
@@ -4923,30 +5277,115 @@ static inline int rtl8169_fragmented_frame(u32 status)
return (status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag);
}
-static inline void rtl8169_rx_csum(struct sk_buff *skb, u32 opts1)
+static void rtl8169_rx_hash(struct rtl8169_private *tp,
+ struct RxDesc *desc,
+ struct sk_buff *skb)
{
- u32 status = opts1 & (RxProtoMask | RxCSFailMask);
+ u32 rss_header_info;
+ u32 hash_val;
+
+ if (!(tp->dev->features & NETIF_F_RXHASH))
+ return;
+
+ rss_header_info = le32_to_cpu(desc->rss_dword.rss_info);
+
+ if (!(rss_header_info & RXS_RSS_L3_TYPE_MASK))
+ return;
+
+ hash_val = le32_to_cpu(desc->rss_dword.rss_result);
+
+ skb_set_hash(skb, hash_val,
+ (RXS_RSS_L4_TYPE_MASK & rss_header_info) ?
+ PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3);
+}
+
+static void rtl8169_rx_csum(struct rtl8169_private *tp,
+ struct sk_buff *skb,
+ u32 opts1)
+{
+ bool csum_ok = false;
+
+ switch (tp->init_rx_desc_type) {
+ case RX_DESC_TYPE_RSS:
+ if (((opts1 & RX_TCPT_DESC_RSS) && !(opts1 & RX_TCPF_DESC_RSS)) ||
+ ((opts1 & RX_UDPT_DESC_RSS) && !(opts1 & RX_UDPF_DESC_RSS)))
+ csum_ok = true;
+ break;
+ default: {
+ u32 status = opts1 & (RxProtoMask | RxCSFailMask);
- if (status == RxProtoTCP || status == RxProtoUDP)
+ if (status == RxProtoTCP || status == RxProtoUDP)
+ csum_ok = true;
+ break;
+ }
+ }
+
+ if (csum_ok)
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
skb_checksum_none_assert(skb);
}
-static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, int budget)
+static __le32 rtl8169_rx_desc_opts1(struct rtl8169_private *tp, struct RxDesc *desc)
+{
+ switch (tp->init_rx_desc_type) {
+ case RX_DESC_TYPE_RSS:
+ return READ_ONCE(desc->rss_opts1);
+ default:
+ return READ_ONCE(desc->opts1);
+ }
+}
+
+static bool rtl8169_check_rx_desc_error(struct rtl8169_rx_ring *ring,
+ struct rtl8169_private *tp,
+ u32 status)
+{
+ switch (tp->init_rx_desc_type) {
+ case RX_DESC_TYPE_RSS:
+ if (unlikely(status & RX_RES_RSS)) {
+ u64_stats_update_begin(&ring->stats.syncp);
+
+ /* Note: The RTL8127 RSS descriptor layout does not have
+ * an RxRWT (Receive Watchdog Timer / over-length) bit.
+ */
+ if (status & RXRUNT_RSS)
+ ring->stats.rx_length_errors++;
+ if (status & RXCRC_RSS)
+ ring->stats.rx_crc_errors++;
+ u64_stats_update_end(&ring->stats.syncp);
+ return true;
+ }
+ break;
+ default:
+ if (unlikely(status & RxRES)) {
+ u64_stats_update_begin(&ring->stats.syncp);
+ if (status & (RxRWT | RxRUNT))
+ ring->stats.rx_length_errors++;
+ if (status & RxCRC)
+ ring->stats.rx_crc_errors++;
+ u64_stats_update_end(&ring->stats.syncp);
+ return true;
+ }
+ }
+ return false;
+}
+
+static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp,
+ struct rtl8169_rx_ring *ring, int budget,
+ struct napi_struct *napi)
{
struct device *d = tp_to_dev(tp);
int count;
- for (count = 0; count < budget; count++, tp->cur_rx++) {
- unsigned int pkt_size, entry = tp->cur_rx % NUM_RX_DESC;
- struct RxDesc *desc = tp->RxDescArray + entry;
+ for (count = 0; count < budget; count++, ring->cur_rx++) {
+ unsigned int pkt_size, entry = ring->cur_rx % NUM_RX_DESC;
+ struct RxDesc *desc = ring->rx_desc_array + entry;
struct sk_buff *skb;
const void *rx_buf;
dma_addr_t addr;
u32 status;
- status = le32_to_cpu(READ_ONCE(desc->opts1));
+ status = le32_to_cpu(rtl8169_rx_desc_opts1(tp, desc));
if (status & DescOwn)
break;
@@ -4956,23 +5395,31 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, int budget
*/
dma_rmb();
- if (unlikely(status & RxRES)) {
+ if (rtl8169_check_rx_desc_error(ring, tp, status)) {
if (net_ratelimit())
netdev_warn(dev, "Rx ERROR. status = %08x\n",
status);
- dev->stats.rx_errors++;
- if (status & (RxRWT | RxRUNT))
- dev->stats.rx_length_errors++;
- if (status & RxCRC)
- dev->stats.rx_crc_errors++;
+ u64_stats_update_begin(&ring->stats.syncp);
+ ring->stats.rx_errors++;
+ u64_stats_update_end(&ring->stats.syncp);
if (!(dev->features & NETIF_F_RXALL))
goto release_descriptor;
- else if (status & RxRWT || !(status & (RxRUNT | RxCRC)))
- goto release_descriptor;
+
+ if (tp->init_rx_desc_type == RX_DESC_TYPE_DEFAULT) {
+ if (status & RxRWT || !(status & (RxRUNT | RxCRC)))
+ goto release_descriptor;
+ } else {
+ if (!(status & (RXRUNT_RSS | RXCRC_RSS)))
+ goto release_descriptor;
+ }
}
pkt_size = status & GENMASK(13, 0);
+
+ if (unlikely(pkt_size < ETH_HLEN + ETH_FCS_LEN))
+ goto release_descriptor;
+
if (likely(!(dev->features & NETIF_F_RXFCS)))
pkt_size -= ETH_FCS_LEN;
@@ -4980,19 +5427,23 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, int budget
* They are seen as a symptom of over-mtu sized frames.
*/
if (unlikely(rtl8169_fragmented_frame(status))) {
- dev->stats.rx_dropped++;
- dev->stats.rx_length_errors++;
+ u64_stats_update_begin(&ring->stats.syncp);
+ ring->stats.rx_dropped++;
+ ring->stats.rx_length_errors++;
+ u64_stats_update_end(&ring->stats.syncp);
goto release_descriptor;
}
- skb = napi_alloc_skb(&tp->napi, pkt_size);
+ skb = napi_alloc_skb(napi, pkt_size);
if (unlikely(!skb)) {
- dev->stats.rx_dropped++;
+ u64_stats_update_begin(&ring->stats.syncp);
+ ring->stats.rx_dropped++;
+ u64_stats_update_end(&ring->stats.syncp);
goto release_descriptor;
}
- addr = le64_to_cpu(desc->addr);
- rx_buf = page_address(tp->Rx_databuff[entry]);
+ addr = ring->rx_desc_phy_addr[entry];
+ rx_buf = page_address(ring->rx_databuff[entry]);
dma_sync_single_for_cpu(d, addr, pkt_size, DMA_FROM_DEVICE);
prefetch(rx_buf);
@@ -5001,19 +5452,28 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, int budget
skb->len = pkt_size;
dma_sync_single_for_device(d, addr, pkt_size, DMA_FROM_DEVICE);
- rtl8169_rx_csum(skb, status);
+ if (tp->num_rx_rings > 1) {
+ rtl8169_rx_hash(tp, desc, skb);
+ skb_record_rx_queue(skb, ring - tp->rx_ring);
+ }
+ rtl8169_rx_csum(tp, skb, status);
skb->protocol = eth_type_trans(skb, dev);
- rtl8169_rx_vlan_tag(desc, skb);
+ rtl8169_rx_vlan_tag(tp, desc, skb);
- if (skb->pkt_type == PACKET_MULTICAST)
- dev->stats.multicast++;
+ if (skb->pkt_type == PACKET_MULTICAST) {
+ u64_stats_update_begin(&ring->stats.syncp);
+ ring->stats.multicast++;
+ u64_stats_update_end(&ring->stats.syncp);
+ }
- napi_gro_receive(&tp->napi, skb);
+ napi_gro_receive(napi, skb);
dev_sw_netstats_rx_add(dev, pkt_size);
release_descriptor:
- rtl8169_mark_to_asic(desc);
+ if (tp->init_rx_desc_type == RX_DESC_TYPE_RSS)
+ desc->rss_addr = cpu_to_le64(ring->rx_desc_phy_addr[entry]);
+ rtl8169_mark_to_asic(tp, desc);
}
return count;
@@ -5021,8 +5481,12 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, int budget
static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
{
- struct rtl8169_private *tp = dev_instance;
- u32 status = rtl_get_events(tp);
+ struct napi_struct *napi = dev_instance;
+ struct rtl8169_private *tp;
+ u32 status;
+
+ tp = netdev_priv(napi->dev);
+ status = rtl_get_events(tp);
if ((status & 0xffff) == 0xffff || !(status & tp->irq_mask))
return IRQ_NONE;
@@ -5043,13 +5507,127 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
}
rtl_irq_disable(tp);
- napi_schedule(&tp->napi);
+ napi_schedule(napi);
out:
rtl_ack_events(tp, status);
return IRQ_HANDLED;
}
+static void rtl8169_free_one_irq(struct rtl8169_private *tp, int i)
+{
+ struct pci_dev *pdev = tp->pci_dev;
+ struct napi_struct *napi;
+ int irq;
+
+ irq = pci_irq_vector(pdev, i);
+ napi = &tp->rtl8169_napi[i];
+
+ if (tp->irq_nvecs > 1) {
+ if (i <= R8169_MAX_RX_QUEUES)
+ free_irq(irq, napi);
+ else if (i == MSIX_ID_VEC_MAP_LINKCHG)
+ free_irq(irq, tp);
+ } else {
+ free_irq(irq, napi);
+ }
+}
+
+static void rtl8169_free_irq(struct rtl8169_private *tp)
+{
+ int i;
+
+ for (i = 0; i < tp->irq_nvecs; i++)
+ rtl8169_free_one_irq(tp, i);
+}
+
+static void rtl8169_disable_hw_interrupt_msix(struct rtl8169_private *tp,
+ int message_id)
+{
+ RTL_W32(tp, IMR_CLEAR_VEC_MAP_REG, BIT(message_id));
+}
+
+static void rtl8169_clear_hw_isr(struct rtl8169_private *tp, int message_id)
+{
+ RTL_W32(tp, ISR_VEC_MAP_REG, BIT(message_id));
+}
+
+static void rtl8169_enable_hw_interrupt_msix(struct rtl8169_private *tp,
+ int message_id)
+{
+ RTL_W32(tp, IMR_SET_VEC_MAP_REG, BIT(message_id));
+}
+
+static irqreturn_t rtl8169_interrupt_msix(int irq, void *dev_instance)
+{
+ struct napi_struct *napi = dev_instance;
+ struct net_device *dev = napi->dev;
+ struct rtl8169_private *tp;
+ int message_id;
+
+ tp = netdev_priv(dev);
+ message_id = napi - tp->rtl8169_napi;
+
+ rtl8169_disable_hw_interrupt_msix(tp, message_id);
+ rtl8169_clear_hw_isr(tp, message_id);
+
+ napi_schedule(napi);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t rtl8169_interrupt_other(int irq, void *dev_instance)
+{
+ struct rtl8169_private *tp = dev_instance;
+
+ rtl8169_clear_hw_isr(tp, MSIX_ID_VEC_MAP_LINKCHG);
+ if (tp->phydev)
+ phy_mac_interrupt(tp->phydev);
+ else if (tp->sfp_mode)
+ phylink_mac_change(tp->phylink,
+ !!(RTL_R8(tp, PHYstatus) & LinkStatus));
+ return IRQ_HANDLED;
+}
+
+static int rtl8169_request_irq(struct rtl8169_private *tp)
+{
+ struct pci_dev *pdev = tp->pci_dev;
+ struct net_device *dev = tp->dev;
+ struct napi_struct *napi;
+ unsigned long irqflags;
+ int i, rc, irq;
+
+ irqflags = pci_dev_msi_enabled(pdev) ? IRQF_NO_THREAD : IRQF_SHARED;
+
+ for (i = 0; i < tp->irq_nvecs; i++) {
+ napi = &tp->rtl8169_napi[i];
+ irq = pci_irq_vector(pdev, i);
+
+ if (tp->irq_nvecs > 1) {
+ /* RX: 0~7, TX: 8*/
+ if (i <= R8169_MAX_RX_QUEUES)
+ rc = request_irq(irq, rtl8169_interrupt_msix,
+ irqflags, dev->name, napi);
+ else if (i == MSIX_ID_VEC_MAP_LINKCHG)
+ rc = request_irq(irq, rtl8169_interrupt_other,
+ irqflags, dev->name, tp);
+ else
+ continue;
+ } else {
+ rc = request_irq(irq, rtl8169_interrupt,
+ irqflags, dev->name, napi);
+ }
+ if (rc)
+ goto free_irq;
+ }
+ return 0;
+
+free_irq:
+ while (--i >= 0)
+ rtl8169_free_one_irq(tp, i);
+ return rc;
+}
+
static void rtl_task(struct work_struct *work)
{
struct rtl8169_private *tp =
@@ -5084,13 +5662,14 @@ static void rtl_task(struct work_struct *work)
static int rtl8169_poll(struct napi_struct *napi, int budget)
{
- struct rtl8169_private *tp = container_of(napi, struct rtl8169_private, napi);
- struct net_device *dev = tp->dev;
- int work_done;
+ struct rtl8169_private *tp = netdev_priv(napi->dev);
+ struct net_device *dev = napi->dev;
+ int work_done = 0;
rtl_tx(dev, tp, budget);
- work_done = rtl_rx(dev, tp, budget);
+ /* rtl8169_poll() is used only when there is a single RX ring. */
+ work_done = rtl_rx(dev, tp, &tp->rx_ring[0], budget, napi);
if (work_done < budget && napi_complete_done(napi, work_done))
rtl_irq_enable(tp);
@@ -5175,7 +5754,7 @@ static void rtl8169_up(struct rtl8169_private *tp)
if (tp->phydev)
rtl8169_init_phy(tp);
- napi_enable(&tp->napi);
+ rtl8169_napi_enable(tp);
enable_work(&tp->wk.work);
rtl_reset_work(tp);
}
@@ -5190,18 +5769,17 @@ static int rtl8169_close(struct net_device *dev)
phylink_stop(tp->phylink);
netif_stop_queue(dev);
rtl8169_down(tp);
- rtl8169_rx_clear(tp);
+ for (int i = 0; i < tp->num_rx_rings; i++)
+ rtl8169_rx_clear(tp, &tp->rx_ring[i]);
- free_irq(tp->irq, tp);
+ rtl8169_free_irq(tp);
phylink_disconnect_phy(tp->phylink);
- dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
- tp->RxPhyAddr);
dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray,
tp->TxPhyAddr);
tp->TxDescArray = NULL;
- tp->RxDescArray = NULL;
+ rtl8169_free_rx_desc(tp);
pm_runtime_put_sync(&pdev->dev);
@@ -5213,7 +5791,13 @@ static void rtl8169_netpoll(struct net_device *dev)
{
struct rtl8169_private *tp = netdev_priv(dev);
- rtl8169_interrupt(tp->irq, tp);
+ if (tp->irq_nvecs > 1) {
+ for (int i = 0; i < tp->num_rx_rings; i++)
+ rtl8169_interrupt_msix(0, &tp->rtl8169_napi[i]);
+ rtl8169_interrupt_msix(0, &tp->rtl8169_napi[R8169_MAX_RX_QUEUES]);
+ } else {
+ rtl8169_interrupt(0, &tp->rtl8169_napi[0]);
+ }
}
#endif
@@ -5221,7 +5805,6 @@ static int rtl_open(struct net_device *dev)
{
struct rtl8169_private *tp = netdev_priv(dev);
struct pci_dev *pdev = tp->pci_dev;
- unsigned long irqflags;
int retval = -ENOMEM;
pm_runtime_get_sync(&pdev->dev);
@@ -5235,10 +5818,8 @@ static int rtl_open(struct net_device *dev)
if (!tp->TxDescArray)
goto out;
- tp->RxDescArray = dma_alloc_coherent(&pdev->dev, R8169_RX_RING_BYTES,
- &tp->RxPhyAddr, GFP_KERNEL);
- if (!tp->RxDescArray)
- goto err_free_tx_0;
+ if (rtl8169_alloc_rx_desc(tp) < 0)
+ goto err_free_rx_1;
retval = rtl8169_init_ring(tp);
if (retval < 0)
@@ -5246,8 +5827,7 @@ static int rtl_open(struct net_device *dev)
rtl_request_firmware(tp);
- irqflags = pci_dev_msi_enabled(pdev) ? IRQF_NO_THREAD : IRQF_SHARED;
- retval = request_irq(tp->irq, rtl8169_interrupt, irqflags, dev->name, tp);
+ retval = rtl8169_request_irq(tp);
if (retval < 0)
goto err_release_fw_2;
@@ -5266,15 +5846,13 @@ static int rtl_open(struct net_device *dev)
return retval;
err_free_irq:
- free_irq(tp->irq, tp);
+ rtl8169_free_irq(tp);
err_release_fw_2:
rtl_release_firmware(tp);
- rtl8169_rx_clear(tp);
+ for (int i = 0; i < tp->num_rx_rings; i++)
+ rtl8169_rx_clear(tp, &tp->rx_ring[i]);
err_free_rx_1:
- dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
- tp->RxPhyAddr);
- tp->RxDescArray = NULL;
-err_free_tx_0:
+ rtl8169_free_rx_desc(tp);
dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray,
tp->TxPhyAddr);
tp->TxDescArray = NULL;
@@ -5293,6 +5871,27 @@ rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
netdev_stats_to_stats64(stats, &dev->stats);
dev_fetch_sw_netstats(stats, dev->tstats);
+ for (int i = 0; i < tp->num_rx_rings; i++) {
+ u64 errors, dropped, length_errors, crc_errors, multicast;
+ struct rtl8169_rx_ring *ring = &tp->rx_ring[i];
+ unsigned int start;
+
+ do {
+ start = u64_stats_fetch_begin(&ring->stats.syncp);
+ errors = ring->stats.rx_errors;
+ dropped = ring->stats.rx_dropped;
+ length_errors = ring->stats.rx_length_errors;
+ crc_errors = ring->stats.rx_crc_errors;
+ multicast = ring->stats.multicast;
+ } while (u64_stats_fetch_retry(&ring->stats.syncp, start));
+
+ stats->rx_errors += errors;
+ stats->rx_dropped += dropped;
+ stats->rx_length_errors += length_errors;
+ stats->rx_crc_errors += crc_errors;
+ stats->multicast += multicast;
+ }
+
/*
* Fetch additional counter values missing in stats collected by driver
* from tally counters.
@@ -5419,6 +6018,19 @@ static void rtl_shutdown(struct pci_dev *pdev)
pci_prepare_to_sleep(pdev);
}
+static void r8169_free_napi(struct rtl8169_private *tp)
+{
+ if (tp->irq_nvecs > 1) {
+ for (int i = 0; i < tp->num_rx_rings; i++)
+ netif_napi_del(&tp->rtl8169_napi[i]);
+ netif_napi_del(&tp->rtl8169_napi[R8169_MAX_RX_QUEUES]);
+ } else {
+ netif_napi_del(&tp->rtl8169_napi[0]);
+ }
+
+ kfree(tp->rtl8169_napi);
+}
+
static void rtl_remove_one(struct pci_dev *pdev)
{
struct rtl8169_private *tp = pci_get_drvdata(pdev);
@@ -5432,6 +6044,8 @@ static void rtl_remove_one(struct pci_dev *pdev)
r8169_remove_leds(tp->leds);
unregister_netdev(tp->dev);
+ r8169_free_napi(tp);
+ kfree(tp->rx_ring);
phylink_destroy(tp->phylink);
if (tp->dash_type != RTL_DASH_NONE)
@@ -5465,15 +6079,49 @@ static const struct net_device_ops rtl_netdev_ops = {
static void rtl_set_irq_mask(struct rtl8169_private *tp)
{
- tp->irq_mask = RxOK | RxErr | TxOK | TxErr | LinkChg;
+ if (tp->irq_nvecs > 1) {
+ tp->irq_mask = ISRIMR_LINKCHG | ISRIMR_TOK_Q0;
+ for (int i = 0; i < tp->num_rx_rings; i++)
+ tp->irq_mask |= ISRIMR_ROK_Q0 << i;
+ } else {
+ tp->irq_mask = RxOK | RxErr | TxOK | TxErr | LinkChg;
- if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
- tp->irq_mask |= SYSErr | RxFIFOOver;
+ if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
+ tp->irq_mask |= SYSErr | RxFIFOOver;
+ }
+}
+
+static int get_max_irq_nvecs(struct rtl8169_private *tp)
+{
+ if (tp->mac_version == RTL_GIGA_MAC_VER_80)
+ return R8127_MAX_NUM_IRQVEC;
+ return R8169_IRQ_DEFAULT;
+}
+
+static int get_min_irq_nvecs(struct rtl8169_private *tp)
+{
+ if (tp->mac_version == RTL_GIGA_MAC_VER_80)
+ return R8127_MIN_NUM_IRQVEC;
+ return R8169_IRQ_DEFAULT;
+}
+
+static void rtl8169_set_rx_ring_num(struct rtl8169_private *tp)
+{
+ if (tp->irq_nvecs >= get_min_irq_nvecs(tp)) {
+ unsigned int rss_queue_num = netif_get_num_default_rss_queues();
+
+ tp->num_rx_rings = rounddown_pow_of_two(min(rss_queue_num,
+ tp->hw_supp_num_rx_queues));
+ if (tp->num_rx_rings >= 2)
+ tp->init_rx_desc_type = RX_DESC_TYPE_RSS;
+ }
}
static int rtl_alloc_irq(struct rtl8169_private *tp)
{
+ struct pci_dev *pdev = tp->pci_dev;
unsigned int flags;
+ int nvecs;
switch (tp->mac_version) {
case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06:
@@ -5489,7 +6137,21 @@ static int rtl_alloc_irq(struct rtl8169_private *tp)
break;
}
- return pci_alloc_irq_vectors(tp->pci_dev, 1, 1, flags);
+ nvecs = pci_alloc_irq_vectors(pdev, get_min_irq_nvecs(tp),
+ get_max_irq_nvecs(tp), flags);
+
+ if (nvecs < 0) {
+ dev_info(&pdev->dev, "Failed to allocate %d MSI-X vectors.\n",
+ get_min_irq_nvecs(tp));
+ nvecs = pci_alloc_irq_vectors(pdev, 1, 1, flags);
+ }
+
+ if (nvecs < 0)
+ return nvecs;
+
+ tp->irq_nvecs = nvecs;
+
+ return 0;
}
static void rtl_read_mac_address(struct rtl8169_private *tp,
@@ -6005,6 +6667,117 @@ static int rtl_init_phylink(struct rtl8169_private *tp)
return 0;
}
+static int rtl8169_poll_msix_rx(struct napi_struct *napi, int budget)
+{
+ struct net_device *dev = napi->dev;
+ struct rtl8169_private *tp;
+ int work_done = 0;
+ int message_id;
+
+ tp = netdev_priv(dev);
+ message_id = napi - tp->rtl8169_napi;
+
+ if (message_id < tp->num_rx_rings)
+ work_done += rtl_rx(dev, tp, &tp->rx_ring[message_id],
+ budget, napi);
+
+ if (work_done < budget && napi_complete_done(napi, work_done))
+ rtl8169_enable_hw_interrupt_msix(tp, message_id);
+
+ return work_done;
+}
+
+static int rtl8169_poll_msix_tx(struct napi_struct *napi, int budget)
+{
+ struct net_device *dev = napi->dev;
+ struct rtl8169_private *tp;
+
+ tp = netdev_priv(dev);
+
+ /* Currently r8169 only supports a single Tx ring.
+ * Therefore, we don't need a per-ring Tx processing loop here.
+ */
+ rtl_tx(dev, tp, budget);
+
+ if (budget && napi_complete_done(napi, 0))
+ rtl8169_enable_hw_interrupt_msix(tp, (int)(napi - tp->rtl8169_napi));
+
+ return 0;
+}
+
+/* RTL8127 MSI-X vector layout:
+ * Vectors 0 .. (MAX_RXQ - 1) : Rx Queues
+ * Vectors MAX_RXQ .. (MAX_RXQ + MAX_TXQ - 1) : Tx Queues
+ * NAPI is only allocated for data path
+ */
+static void r8169_init_napi(struct rtl8169_private *tp)
+{
+ int i;
+
+ if (tp->irq_nvecs > 1) {
+ for (i = 0; i < tp->num_rx_rings; i++) {
+ netif_napi_add(tp->dev, &tp->rtl8169_napi[i],
+ rtl8169_poll_msix_rx);
+ netif_napi_set_irq(&tp->rtl8169_napi[i],
+ pci_irq_vector(tp->pci_dev, i));
+ }
+ netif_napi_add_tx(tp->dev,
+ &tp->rtl8169_napi[R8169_MAX_RX_QUEUES],
+ rtl8169_poll_msix_tx);
+ netif_napi_set_irq(&tp->rtl8169_napi[R8169_MAX_RX_QUEUES],
+ pci_irq_vector(tp->pci_dev, R8169_MAX_RX_QUEUES));
+ } else {
+ netif_napi_add(tp->dev, &tp->rtl8169_napi[0], rtl8169_poll);
+ netif_napi_set_irq(&tp->rtl8169_napi[0],
+ pci_irq_vector(tp->pci_dev, 0));
+ }
+}
+
+static void rtl8169_get_channels(struct net_device *dev,
+ struct ethtool_channels *ch)
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+
+ if (tp->irq_nvecs > 1) {
+ ch->max_rx = tp->hw_supp_num_rx_queues;
+ ch->max_tx = 1;
+ ch->rx_count = tp->num_rx_rings;
+ ch->tx_count = 1;
+ } else {
+ ch->max_combined = 1;
+ ch->combined_count = 1;
+ }
+}
+
+static const struct ethtool_ops rtl8169_ethtool_ops = {
+ .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
+ ETHTOOL_COALESCE_MAX_FRAMES,
+ .get_drvinfo = rtl8169_get_drvinfo,
+ .get_regs_len = rtl8169_get_regs_len,
+ .get_link = ethtool_op_get_link,
+ .get_coalesce = rtl_get_coalesce,
+ .set_coalesce = rtl_set_coalesce,
+ .get_regs = rtl8169_get_regs,
+ .get_wol = rtl8169_get_wol,
+ .set_wol = rtl8169_set_wol,
+ .get_strings = rtl8169_get_strings,
+ .get_sset_count = rtl8169_get_sset_count,
+ .get_ethtool_stats = rtl8169_get_ethtool_stats,
+ .get_ts_info = ethtool_op_get_ts_info,
+ .nway_reset = rtl8169_nway_reset,
+ .get_eee = rtl8169_get_eee,
+ .set_eee = rtl8169_set_eee,
+ .get_channels = rtl8169_get_channels,
+ .get_link_ksettings = rtl8169_get_link_ksettings,
+ .set_link_ksettings = rtl8169_set_link_ksettings,
+ .get_ringparam = rtl8169_get_ringparam,
+ .get_pause_stats = rtl8169_get_pause_stats,
+ .get_pauseparam = rtl8169_get_pauseparam,
+ .set_pauseparam = rtl8169_set_pauseparam,
+ .get_eth_mac_stats = rtl8169_get_eth_mac_stats,
+ .get_eth_ctrl_stats = rtl8169_get_eth_ctrl_stats,
+};
+
static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
const struct rtl_chip_info *chip;
@@ -6015,7 +6788,10 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
u32 txconfig;
u32 xid;
- dev = devm_alloc_etherdev(&pdev->dev, sizeof (*tp));
+ dev = devm_alloc_etherdev_mqs(&pdev->dev, sizeof(*tp),
+ R8169_MAX_TX_QUEUES,
+ R8169_MAX_RX_QUEUES);
+
if (!dev)
return -ENOMEM;
@@ -6091,6 +6867,13 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
tp->dash_type = rtl_get_dash_type(tp);
tp->dash_enabled = rtl_dash_is_enabled(tp);
+ if (rtl_hw_support_rss(tp)) {
+ tp->rss_data = devm_kzalloc(&pdev->dev, sizeof(*tp->rss_data),
+ GFP_KERNEL);
+ if (!tp->rss_data)
+ return -ENOMEM;
+ }
+
tp->cp_cmd = RTL_R16(tp, CPlusCmd) & CPCMD_MASK;
if (sizeof(dma_addr_t) > 4 && tp->mac_version >= RTL_GIGA_MAC_VER_18 &&
@@ -6105,11 +6888,16 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
rtl_hw_reset(tp);
+ rtl_setup_rx_params(tp);
+
rc = rtl_alloc_irq(tp);
if (rc < 0)
return dev_err_probe(&pdev->dev, rc, "Can't allocate interrupt\n");
- tp->irq = pci_irq_vector(pdev, 0);
+ rtl8169_set_rx_ring_num(tp);
+
+ if (rtl_hw_support_rss(tp))
+ rtl8169_init_rss(tp);
INIT_WORK(&tp->wk.work, rtl_task);
disable_work(&tp->wk.work);
@@ -6118,13 +6906,16 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->ethtool_ops = &rtl8169_ethtool_ops;
- netif_napi_add(dev, &tp->napi, rtl8169_poll);
-
dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
+ if (rtl_hw_support_rss(tp) && tp->num_rx_rings > 1) {
+ dev->hw_features |= NETIF_F_RXHASH;
+ dev->features |= NETIF_F_RXHASH;
+ }
+
/*
* Pretend we are using VLANs; This bypasses a nasty bug where
* Interrupts stop flowing on high load on 8110SCd controllers.
@@ -6180,6 +6971,10 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (jumbo_max)
dev->max_mtu = jumbo_max;
+ rc = netif_set_real_num_queues(tp->dev, 1, tp->num_rx_rings);
+ if (rc < 0)
+ return dev_err_probe(&pdev->dev, rc, "set tx/rx num failure\n");
+
rtl_set_irq_mask(tp);
tp->counters = dmam_alloc_coherent (&pdev->dev, sizeof(*tp->counters),
@@ -6202,12 +6997,29 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
}
- rc = register_netdev(dev);
- if (rc) {
- phylink_destroy(tp->phylink);
- return rc;
+ tp->rx_ring = kcalloc(tp->num_rx_rings, sizeof(struct rtl8169_rx_ring),
+ GFP_KERNEL);
+ if (!tp->rx_ring) {
+ rc = -ENOMEM;
+ goto err_destory_phylink;
+ }
+
+ for (int i = 0; i < tp->num_rx_rings; i++)
+ u64_stats_init(&tp->rx_ring[i].stats.syncp);
+
+ tp->rtl8169_napi = kcalloc(tp->irq_nvecs, sizeof(struct napi_struct),
+ GFP_KERNEL);
+ if (!tp->rtl8169_napi) {
+ rc = -ENOMEM;
+ goto err_free_rx_ring;
}
+ r8169_init_napi(tp);
+
+ rc = register_netdev(dev);
+ if (rc)
+ goto err_free_napi;
+
if (IS_ENABLED(CONFIG_R8169_LEDS)) {
if (rtl_is_8125(tp))
tp->leds = rtl8125_init_leds(dev);
@@ -6215,8 +7027,9 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
tp->leds = rtl8168_init_leds(dev);
}
- netdev_info(dev, "%s, %pM, %sXID %x, IRQ %d\n",
- chip->name, dev->dev_addr, ext_xid_str, xid, tp->irq);
+ netdev_info(dev, "%s, %pM, %sXID %x, IRQ %d (%u total)\n",
+ chip->name, dev->dev_addr, ext_xid_str, xid,
+ pci_irq_vector(pdev, 0), tp->irq_nvecs);
if (jumbo_max)
netdev_info(dev, "jumbo features [frames: %d bytes, tx checksumming: %s]\n",
@@ -6236,6 +7049,14 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
pm_runtime_put_sync(&pdev->dev);
return 0;
+
+err_free_napi:
+ r8169_free_napi(tp);
+err_free_rx_ring:
+ kfree(tp->rx_ring);
+err_destory_phylink:
+ phylink_destroy(tp->phylink);
+ return rc;
}
static struct pci_driver rtl8169_pci_driver = {
|
| 3/2 | 2026/09/29 07:21 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 25917 output: 49 thoughts: 291 Thoughts: **Analyzing a Kernel Patch in the r8169 Driver** Okay, so I see this patch is touching `drivers/net/ethernet/realtek/r8169_main.c`. My first thought is always to understand what's being changed and whether this is a promising area for fuzzing. The `r8169` driver, right? That handles Realtek's PCIe and PCI Ethernet controllers – the 8169, 8168, 8125, that whole family. Now the real question: is this even *reachable* in a typical fuzzing setup? Can I emulate this hardware? The first thing that jumps to mind is QEMU. Let me see, QEMU has the old `rtl8139`, but does it emulate `r8169` or `rtl8168`? I need to know this! Wait, hold on... doesn't `rtl8139` use `8139too.c` or `8139cp.c`? That's right, those are the drivers for the *older* 8139 chipset. Let me see... I recall the PCI ID for `rtl8139` is `10ec:8139`. That's a good data point. Now, to be sure, I need to check the PCI ID table within *this* driver, `r8169_main.c` itself. Knowing those IDs is going to be key to reaching this code during fuzzing. |
| 4/2 | 2026/09/29 07:21 | tool | grepper |
0mArgs:{
"Expression": "RTL_GIGA_MAC_VER_",
"PathPrefix": "drivers/net/ethernet/realtek/r8169_main.c"
}Results: {
"Output": "\nFull output is too long, showing 500 out of 768 lines.\nUse more precise expression if possible.\n\ndrivers/net/ethernet/realtek/r8169_main.c=137=static const struct rtl_chip_info {\n--\ndrivers/net/ethernet/realtek/r8169_main.c-144-\t/* 8127A family. */\ndrivers/net/ethernet/realtek/r8169_main.c:145:\t{ 0x7cf, 0x6c9,\tRTL_GIGA_MAC_VER_80, \"RTL8127A\", FIRMWARE_8127A_1 },\ndrivers/net/ethernet/realtek/r8169_main.c-146-\ndrivers/net/ethernet/realtek/r8169_main.c-147-\t/* 8126A family. */\ndrivers/net/ethernet/realtek/r8169_main.c:148:\t{ 0x7cf, 0x64a,\tRTL_GIGA_MAC_VER_70, \"RTL8126A\", FIRMWARE_8126A_3 },\ndrivers/net/ethernet/realtek/r8169_main.c:149:\t{ 0x7cf, 0x649,\tRTL_GIGA_MAC_VER_70, \"RTL8126A\", FIRMWARE_8126A_2 },\ndrivers/net/ethernet/realtek/r8169_main.c-150-\ndrivers/net/ethernet/realtek/r8169_main.c-151-\t/* 8125BP family. */\ndrivers/net/ethernet/realtek/r8169_main.c:152:\t{ 0x7cf, 0x681,\tRTL_GIGA_MAC_VER_66, \"RTL8125BP\", FIRMWARE_8125BP_2 },\ndrivers/net/ethernet/realtek/r8169_main.c-153-\ndrivers/net/ethernet/realtek/r8169_main.c-154-\t/* 8125CP family*/\ndrivers/net/ethernet/realtek/r8169_main.c:155:\t{ 0x7cf, 0x708, RTL_GIGA_MAC_VER_65, \"RTL8125CP\", FIRMWARE_8125CP_1 },\ndrivers/net/ethernet/realtek/r8169_main.c-156-\ndrivers/net/ethernet/realtek/r8169_main.c-157-\t/* 8125D family. */\ndrivers/net/ethernet/realtek/r8169_main.c:158:\t{ 0x7cf, 0x68b, RTL_GIGA_MAC_VER_64, \"RTL9151A\", FIRMWARE_9151A_1 },\ndrivers/net/ethernet/realtek/r8169_main.c:159:\t{ 0x7cf, 0x68a, RTL_GIGA_MAC_VER_64, \"RTL8125K\", FIRMWARE_8125K_1 },\ndrivers/net/ethernet/realtek/r8169_main.c:160:\t{ 0x7cf, 0x689,\tRTL_GIGA_MAC_VER_64, \"RTL8125D\", FIRMWARE_8125D_2 },\ndrivers/net/ethernet/realtek/r8169_main.c:161:\t{ 0x7cf, 0x688,\tRTL_GIGA_MAC_VER_64, \"RTL8125D\", FIRMWARE_8125D_1 },\ndrivers/net/ethernet/realtek/r8169_main.c-162-\ndrivers/net/ethernet/realtek/r8169_main.c-163-\t/* 8125B family. */\ndrivers/net/ethernet/realtek/r8169_main.c:164:\t{ 0x7cf, 0x641,\tRTL_GIGA_MAC_VER_63, \"RTL8125B\", FIRMWARE_8125B_2 },\ndrivers/net/ethernet/realtek/r8169_main.c-165-\ndrivers/net/ethernet/realtek/r8169_main.c-166-\t/* 8125A family. */\ndrivers/net/ethernet/realtek/r8169_main.c:167:\t{ 0x7cf, 0x609,\tRTL_GIGA_MAC_VER_61, \"RTL8125A\", FIRMWARE_8125A_3 },\ndrivers/net/ethernet/realtek/r8169_main.c-168-\ndrivers/net/ethernet/realtek/r8169_main.c-169-\t/* RTL8117 */\ndrivers/net/ethernet/realtek/r8169_main.c:170:\t{ 0x7cf, 0x54b,\tRTL_GIGA_MAC_VER_52, \"RTL8168fp/RTL8117\" },\ndrivers/net/ethernet/realtek/r8169_main.c:171:\t{ 0x7cf, 0x54a,\tRTL_GIGA_MAC_VER_52, \"RTL8168fp/RTL8117\",\ndrivers/net/ethernet/realtek/r8169_main.c-172-\t FIRMWARE_8168FP_3 },\n--\ndrivers/net/ethernet/realtek/r8169_main.c-174-\t/* 8168EP family. */\ndrivers/net/ethernet/realtek/r8169_main.c:175:\t{ 0x7cf, 0x502,\tRTL_GIGA_MAC_VER_51, \"RTL8168ep/8111ep\" },\ndrivers/net/ethernet/realtek/r8169_main.c-176-\ndrivers/net/ethernet/realtek/r8169_main.c-177-\t/* 8168H family. */\ndrivers/net/ethernet/realtek/r8169_main.c:178:\t{ 0x7cf, 0x541,\tRTL_GIGA_MAC_VER_46, \"RTL8168h/8111h\",\ndrivers/net/ethernet/realtek/r8169_main.c-179-\t FIRMWARE_8168H_2 },\ndrivers/net/ethernet/realtek/r8169_main.c-180-\t/* Realtek calls it RTL8168M, but it's handled like RTL8168H */\ndrivers/net/ethernet/realtek/r8169_main.c:181:\t{ 0x7cf, 0x6c0,\tRTL_GIGA_MAC_VER_46, \"RTL8168M\", FIRMWARE_8168H_2 },\ndrivers/net/ethernet/realtek/r8169_main.c-182-\ndrivers/net/ethernet/realtek/r8169_main.c-183-\t/* 8168G family. */\ndrivers/net/ethernet/realtek/r8169_main.c:184:\t{ 0x7cf, 0x5c8,\tRTL_GIGA_MAC_VER_44, \"RTL8411b\", FIRMWARE_8411_2 },\ndrivers/net/ethernet/realtek/r8169_main.c:185:\t{ 0x7cf, 0x509,\tRTL_GIGA_MAC_VER_42, \"RTL8168gu/8111gu\",\ndrivers/net/ethernet/realtek/r8169_main.c-186-\t FIRMWARE_8168G_3 },\ndrivers/net/ethernet/realtek/r8169_main.c:187:\t{ 0x7cf, 0x4c0,\tRTL_GIGA_MAC_VER_40, \"RTL8168g/8111g\",\ndrivers/net/ethernet/realtek/r8169_main.c-188-\t FIRMWARE_8168G_2 },\n--\ndrivers/net/ethernet/realtek/r8169_main.c-190-\t/* 8168F family. */\ndrivers/net/ethernet/realtek/r8169_main.c:191:\t{ 0x7c8, 0x488,\tRTL_GIGA_MAC_VER_38, \"RTL8411\", FIRMWARE_8411_1 },\ndrivers/net/ethernet/realtek/r8169_main.c:192:\t{ 0x7cf, 0x481,\tRTL_GIGA_MAC_VER_36, \"RTL8168f/8111f\",\ndrivers/net/ethernet/realtek/r8169_main.c-193-\t FIRMWARE_8168F_2 },\ndrivers/net/ethernet/realtek/r8169_main.c:194:\t{ 0x7cf, 0x480,\tRTL_GIGA_MAC_VER_35, \"RTL8168f/8111f\",\ndrivers/net/ethernet/realtek/r8169_main.c-195-\t FIRMWARE_8168F_1 },\n--\ndrivers/net/ethernet/realtek/r8169_main.c-197-\t/* 8168E family. */\ndrivers/net/ethernet/realtek/r8169_main.c:198:\t{ 0x7c8, 0x2c8,\tRTL_GIGA_MAC_VER_34, \"RTL8168evl/8111evl\",\ndrivers/net/ethernet/realtek/r8169_main.c-199-\t FIRMWARE_8168E_3 },\ndrivers/net/ethernet/realtek/r8169_main.c:200:\t{ 0x7cf, 0x2c1,\tRTL_GIGA_MAC_VER_32, \"RTL8168e/8111e\",\ndrivers/net/ethernet/realtek/r8169_main.c-201-\t FIRMWARE_8168E_1 },\ndrivers/net/ethernet/realtek/r8169_main.c:202:\t{ 0x7c8, 0x2c0,\tRTL_GIGA_MAC_VER_33, \"RTL8168e/8111e\",\ndrivers/net/ethernet/realtek/r8169_main.c-203-\t FIRMWARE_8168E_2 },\n--\ndrivers/net/ethernet/realtek/r8169_main.c-205-\t/* 8168D family. */\ndrivers/net/ethernet/realtek/r8169_main.c:206:\t{ 0x7cf, 0x281,\tRTL_GIGA_MAC_VER_25, \"RTL8168d/8111d\",\ndrivers/net/ethernet/realtek/r8169_main.c-207-\t FIRMWARE_8168D_1 },\ndrivers/net/ethernet/realtek/r8169_main.c:208:\t{ 0x7c8, 0x280,\tRTL_GIGA_MAC_VER_26, \"RTL8168d/8111d\",\ndrivers/net/ethernet/realtek/r8169_main.c-209-\t FIRMWARE_8168D_2 },\n--\ndrivers/net/ethernet/realtek/r8169_main.c-211-\t/* 8168DP family. */\ndrivers/net/ethernet/realtek/r8169_main.c:212:\t{ 0x7cf, 0x28a,\tRTL_GIGA_MAC_VER_28, \"RTL8168dp/8111dp\" },\ndrivers/net/ethernet/realtek/r8169_main.c:213:\t{ 0x7cf, 0x28b,\tRTL_GIGA_MAC_VER_31, \"RTL8168dp/8111dp\" },\ndrivers/net/ethernet/realtek/r8169_main.c-214-\ndrivers/net/ethernet/realtek/r8169_main.c-215-\t/* 8168C family. */\ndrivers/net/ethernet/realtek/r8169_main.c:216:\t{ 0x7cf, 0x3c9,\tRTL_GIGA_MAC_VER_23, \"RTL8168cp/8111cp\" },\ndrivers/net/ethernet/realtek/r8169_main.c:217:\t{ 0x7cf, 0x3c8,\tRTL_GIGA_MAC_VER_18, \"RTL8168cp/8111cp\" },\ndrivers/net/ethernet/realtek/r8169_main.c:218:\t{ 0x7c8, 0x3c8,\tRTL_GIGA_MAC_VER_24, \"RTL8168cp/8111cp\" },\ndrivers/net/ethernet/realtek/r8169_main.c:219:\t{ 0x7cf, 0x3c0,\tRTL_GIGA_MAC_VER_19, \"RTL8168c/8111c\" },\ndrivers/net/ethernet/realtek/r8169_main.c:220:\t{ 0x7cf, 0x3c2,\tRTL_GIGA_MAC_VER_20, \"RTL8168c/8111c\" },\ndrivers/net/ethernet/realtek/r8169_main.c:221:\t{ 0x7cf, 0x3c3,\tRTL_GIGA_MAC_VER_21, \"RTL8168c/8111c\" },\ndrivers/net/ethernet/realtek/r8169_main.c:222:\t{ 0x7c8, 0x3c0,\tRTL_GIGA_MAC_VER_22, \"RTL8168c/8111c\" },\ndrivers/net/ethernet/realtek/r8169_main.c-223-\ndrivers/net/ethernet/realtek/r8169_main.c-224-\t/* 8168B family. */\ndrivers/net/ethernet/realtek/r8169_main.c:225:\t{ 0x7c8, 0x380,\tRTL_GIGA_MAC_VER_17, \"RTL8168b/8111b\" },\ndrivers/net/ethernet/realtek/r8169_main.c-226-\t/* This one is very old and rare, support has been removed.\ndrivers/net/ethernet/realtek/r8169_main.c:227:\t * { 0x7c8, 0x300, RTL_GIGA_MAC_VER_11, \"RTL8168b/8111b\" },\ndrivers/net/ethernet/realtek/r8169_main.c-228-\t */\n--\ndrivers/net/ethernet/realtek/r8169_main.c-230-\t/* 8101 family. */\ndrivers/net/ethernet/realtek/r8169_main.c:231:\t{ 0x7c8, 0x448,\tRTL_GIGA_MAC_VER_39, \"RTL8106e\", FIRMWARE_8106E_1 },\ndrivers/net/ethernet/realtek/r8169_main.c:232:\t{ 0x7c8, 0x440,\tRTL_GIGA_MAC_VER_37, \"RTL8402\", FIRMWARE_8402_1 },\ndrivers/net/ethernet/realtek/r8169_main.c:233:\t{ 0x7cf, 0x409,\tRTL_GIGA_MAC_VER_29, \"RTL8105e\", FIRMWARE_8105E_1 },\ndrivers/net/ethernet/realtek/r8169_main.c:234:\t{ 0x7c8, 0x408,\tRTL_GIGA_MAC_VER_30, \"RTL8105e\", FIRMWARE_8105E_1 },\ndrivers/net/ethernet/realtek/r8169_main.c:235:\t{ 0x7cf, 0x349,\tRTL_GIGA_MAC_VER_08, \"RTL8102e\" },\ndrivers/net/ethernet/realtek/r8169_main.c:236:\t{ 0x7cf, 0x249,\tRTL_GIGA_MAC_VER_08, \"RTL8102e\" },\ndrivers/net/ethernet/realtek/r8169_main.c:237:\t{ 0x7cf, 0x348,\tRTL_GIGA_MAC_VER_07, \"RTL8102e\" },\ndrivers/net/ethernet/realtek/r8169_main.c:238:\t{ 0x7cf, 0x248,\tRTL_GIGA_MAC_VER_07, \"RTL8102e\" },\ndrivers/net/ethernet/realtek/r8169_main.c:239:\t{ 0x7cf, 0x240,\tRTL_GIGA_MAC_VER_14, \"RTL8401\" },\ndrivers/net/ethernet/realtek/r8169_main.c:240:\t{ 0x7c8, 0x348,\tRTL_GIGA_MAC_VER_09, \"RTL8102e/RTL8103e\" },\ndrivers/net/ethernet/realtek/r8169_main.c:241:\t{ 0x7c8, 0x248,\tRTL_GIGA_MAC_VER_09, \"RTL8102e/RTL8103e\" },\ndrivers/net/ethernet/realtek/r8169_main.c:242:\t{ 0x7c8, 0x340,\tRTL_GIGA_MAC_VER_10, \"RTL8101e/RTL8100e\" },\ndrivers/net/ethernet/realtek/r8169_main.c-243-\ndrivers/net/ethernet/realtek/r8169_main.c-244-\t/* 8110 family. */\ndrivers/net/ethernet/realtek/r8169_main.c:245:\t{ 0xfc8, 0x980,\tRTL_GIGA_MAC_VER_06, \"RTL8169sc/8110sc\" },\ndrivers/net/ethernet/realtek/r8169_main.c:246:\t{ 0xfc8, 0x180,\tRTL_GIGA_MAC_VER_05, \"RTL8169sc/8110sc\" },\ndrivers/net/ethernet/realtek/r8169_main.c:247:\t{ 0xfc8, 0x100,\tRTL_GIGA_MAC_VER_04, \"RTL8169sb/8110sb\" },\ndrivers/net/ethernet/realtek/r8169_main.c:248:\t{ 0xfc8, 0x040,\tRTL_GIGA_MAC_VER_03, \"RTL8110s\" },\ndrivers/net/ethernet/realtek/r8169_main.c:249:\t{ 0xfc8, 0x008,\tRTL_GIGA_MAC_VER_02, \"RTL8169s\" },\ndrivers/net/ethernet/realtek/r8169_main.c-250-\ndrivers/net/ethernet/realtek/r8169_main.c-251-\t/* extended chip version*/\ndrivers/net/ethernet/realtek/r8169_main.c:252:\t{ 0x7cf, 0x7c8, RTL_GIGA_MAC_VER_EXTENDED },\ndrivers/net/ethernet/realtek/r8169_main.c-253-\n--\ndrivers/net/ethernet/realtek/r8169_main.c=258=static const struct rtl_chip_info rtl_chip_infos_extended[] = {\ndrivers/net/ethernet/realtek/r8169_main.c:259:\t{ 0x7fffffff, 0x00000000, RTL_GIGA_MAC_VER_64, \"RTL9151AS\",\ndrivers/net/ethernet/realtek/r8169_main.c-260-\t FIRMWARE_9151A_1},\n--\ndrivers/net/ethernet/realtek/r8169_main.c=993=static bool rtl_is_8125(struct rtl8169_private *tp)\ndrivers/net/ethernet/realtek/r8169_main.c-994-{\ndrivers/net/ethernet/realtek/r8169_main.c:995:\treturn tp-\u003emac_version \u003e= RTL_GIGA_MAC_VER_61;\ndrivers/net/ethernet/realtek/r8169_main.c-996-}\n--\ndrivers/net/ethernet/realtek/r8169_main.c=998=static bool rtl_is_8168evl_up(struct rtl8169_private *tp)\ndrivers/net/ethernet/realtek/r8169_main.c-999-{\ndrivers/net/ethernet/realtek/r8169_main.c:1000:\treturn tp-\u003emac_version \u003e= RTL_GIGA_MAC_VER_34 \u0026\u0026\ndrivers/net/ethernet/realtek/r8169_main.c:1001:\t tp-\u003emac_version != RTL_GIGA_MAC_VER_39 \u0026\u0026\ndrivers/net/ethernet/realtek/r8169_main.c:1002:\t tp-\u003emac_version \u003c= RTL_GIGA_MAC_VER_52;\ndrivers/net/ethernet/realtek/r8169_main.c-1003-}\n--\ndrivers/net/ethernet/realtek/r8169_main.c=1005=static bool rtl_supports_eee(struct rtl8169_private *tp)\ndrivers/net/ethernet/realtek/r8169_main.c-1006-{\ndrivers/net/ethernet/realtek/r8169_main.c:1007:\treturn tp-\u003emac_version \u003e= RTL_GIGA_MAC_VER_34 \u0026\u0026\ndrivers/net/ethernet/realtek/r8169_main.c:1008:\t tp-\u003emac_version != RTL_GIGA_MAC_VER_37 \u0026\u0026\ndrivers/net/ethernet/realtek/r8169_main.c:1009:\t tp-\u003emac_version != RTL_GIGA_MAC_VER_39;\ndrivers/net/ethernet/realtek/r8169_main.c-1010-}\n--\ndrivers/net/ethernet/realtek/r8169_main.c=1167=static void r8168fp_adjust_ocp_cmd(struct rtl8169_private *tp, u32 *cmd, int type)\n--\ndrivers/net/ethernet/realtek/r8169_main.c-1169-\t/* based on RTL8168FP_OOBMAC_BASE in vendor driver */\ndrivers/net/ethernet/realtek/r8169_main.c:1170:\tif (type == ERIAR_OOB \u0026\u0026 tp-\u003emac_version == RTL_GIGA_MAC_VER_52)\ndrivers/net/ethernet/realtek/r8169_main.c-1171-\t\t*cmd |= 0xf70 \u003c\u003c 18;\n--\ndrivers/net/ethernet/realtek/r8169_main.c=1412=static void rtl_sfp_reset(struct rtl8169_private *tp)\ndrivers/net/ethernet/realtek/r8169_main.c-1413-{\ndrivers/net/ethernet/realtek/r8169_main.c:1414:\tif (tp-\u003emac_version == RTL_GIGA_MAC_VER_80)\ndrivers/net/ethernet/realtek/r8169_main.c-1415-\t\tr8127_sfp_sds_phy_reset(tp);\n--\ndrivers/net/ethernet/realtek/r8169_main.c=1421=static void rtl8168g_phy_suspend_quirk(struct rtl8169_private *tp, int value)\n--\ndrivers/net/ethernet/realtek/r8169_main.c-1423-\tswitch (tp-\u003emac_version) {\ndrivers/net/ethernet/realtek/r8169_main.c:1424:\tcase RTL_GIGA_MAC_VER_40:\ndrivers/net/ethernet/realtek/r8169_main.c-1425-\t\tif (value \u0026 BMCR_RESET || !(value \u0026 BMCR_PDOWN))\n--\ndrivers/net/ethernet/realtek/r8169_main.c=1472=static bool rtl_is_8116af(struct rtl8169_private *tp)\ndrivers/net/ethernet/realtek/r8169_main.c-1473-{\ndrivers/net/ethernet/realtek/r8169_main.c:1474:\treturn tp-\u003emac_version == RTL_GIGA_MAC_VER_52 \u0026\u0026\ndrivers/net/ethernet/realtek/r8169_main.c-1475-\t\t(r8168_mac_ocp_read(tp, RTL_PKG_DETECT) \u0026 RTL_PKG_DETECT_MASK) ==\n--\ndrivers/net/ethernet/realtek/r8169_main.c=1564=static void rtl_writephy(struct rtl8169_private *tp, int location, int val)\n--\ndrivers/net/ethernet/realtek/r8169_main.c-1566-\tswitch (tp-\u003emac_version) {\ndrivers/net/ethernet/realtek/r8169_main.c:1567:\tcase RTL_GIGA_MAC_VER_28:\ndrivers/net/ethernet/realtek/r8169_main.c:1568:\tcase RTL_GIGA_MAC_VER_31:\ndrivers/net/ethernet/realtek/r8169_main.c-1569-\t\tr8168dp_2_mdio_write(tp, location, val);\ndrivers/net/ethernet/realtek/r8169_main.c-1570-\t\tbreak;\ndrivers/net/ethernet/realtek/r8169_main.c:1571:\tcase RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_LAST:\ndrivers/net/ethernet/realtek/r8169_main.c-1572-\t\tr8168g_mdio_write(tp, location, val);\n--\ndrivers/net/ethernet/realtek/r8169_main.c=1580=static int rtl_readphy(struct rtl8169_private *tp, int location)\n--\ndrivers/net/ethernet/realtek/r8169_main.c-1582-\tswitch (tp-\u003emac_version) {\ndrivers/net/ethernet/realtek/r8169_main.c:1583:\tcase RTL_GIGA_MAC_VER_28:\ndrivers/net/ethernet/realtek/r8169_main.c:1584:\tcase RTL_GIGA_MAC_VER_31:\ndrivers/net/ethernet/realtek/r8169_main.c-1585-\t\treturn r8168dp_2_mdio_read(tp, location);\ndrivers/net/ethernet/realtek/r8169_main.c:1586:\tcase RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_LAST:\ndrivers/net/ethernet/realtek/r8169_main.c-1587-\t\treturn r8168g_mdio_read(tp, location);\n--\ndrivers/net/ethernet/realtek/r8169_main.c=1654=static u16 rtl8168_get_ocp_reg(struct rtl8169_private *tp)\ndrivers/net/ethernet/realtek/r8169_main.c-1655-{\ndrivers/net/ethernet/realtek/r8169_main.c:1656:\treturn (tp-\u003emac_version == RTL_GIGA_MAC_VER_31) ? 0xb8 : 0x10;\ndrivers/net/ethernet/realtek/r8169_main.c-1657-}\n--\ndrivers/net/ethernet/realtek/r8169_main.c=1790=static bool rtl_hw_support_rss(struct rtl8169_private *tp)\ndrivers/net/ethernet/realtek/r8169_main.c-1791-{\ndrivers/net/ethernet/realtek/r8169_main.c:1792:\treturn tp-\u003emac_version == RTL_GIGA_MAC_VER_80;\ndrivers/net/ethernet/realtek/r8169_main.c-1793-}\n--\ndrivers/net/ethernet/realtek/r8169_main.c=1795=static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private *tp)\n--\ndrivers/net/ethernet/realtek/r8169_main.c-1797-\tswitch (tp-\u003emac_version) {\ndrivers/net/ethernet/realtek/r8169_main.c:1798:\tcase RTL_GIGA_MAC_VER_28:\ndrivers/net/ethernet/realtek/r8169_main.c:1799:\tcase RTL_GIGA_MAC_VER_31:\ndrivers/net/ethernet/realtek/r8169_main.c-1800-\t\treturn RTL_DASH_DP;\ndrivers/net/ethernet/realtek/r8169_main.c:1801:\tcase RTL_GIGA_MAC_VER_51 ... RTL_GIGA_MAC_VER_52:\ndrivers/net/ethernet/realtek/r8169_main.c-1802-\t\treturn RTL_DASH_EP;\ndrivers/net/ethernet/realtek/r8169_main.c:1803:\tcase RTL_GIGA_MAC_VER_66:\ndrivers/net/ethernet/realtek/r8169_main.c-1804-\t\treturn RTL_DASH_25_BP;\ndrivers/net/ethernet/realtek/r8169_main.c:1805:\tcase RTL_GIGA_MAC_VER_80:\ndrivers/net/ethernet/realtek/r8169_main.c-1806-\t\treturn (tp-\u003epci_dev-\u003erevision == 0x04)\n--\ndrivers/net/ethernet/realtek/r8169_main.c=1814=static void rtl_set_d3_pll_down(struct rtl8169_private *tp, bool enable)\n--\ndrivers/net/ethernet/realtek/r8169_main.c-1816-\tswitch (tp-\u003emac_version) {\ndrivers/net/ethernet/realtek/r8169_main.c:1817:\tcase RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_24:\ndrivers/net/ethernet/realtek/r8169_main.c:1818:\tcase RTL_GIGA_MAC_VER_28:\ndrivers/net/ethernet/realtek/r8169_main.c:1819:\tcase RTL_GIGA_MAC_VER_31:\ndrivers/net/ethernet/realtek/r8169_main.c:1820:\tcase RTL_GIGA_MAC_VER_38:\ndrivers/net/ethernet/realtek/r8169_main.c-1821-\t\tbreak;\ndrivers/net/ethernet/realtek/r8169_main.c:1822:\tcase RTL_GIGA_MAC_VER_80:\ndrivers/net/ethernet/realtek/r8169_main.c-1823-\t\tr8169_mod_reg8_cond(tp, PMCH, D3_NO_PLL_DOWN, true);\n--\ndrivers/net/ethernet/realtek/r8169_main.c=1902=static void rtl_link_chg_patch(struct rtl8169_private *tp, int speed)\ndrivers/net/ethernet/realtek/r8169_main.c-1903-{\ndrivers/net/ethernet/realtek/r8169_main.c:1904:\tif (tp-\u003emac_version == RTL_GIGA_MAC_VER_34 ||\ndrivers/net/ethernet/realtek/r8169_main.c:1905:\t tp-\u003emac_version == RTL_GIGA_MAC_VER_38) {\ndrivers/net/ethernet/realtek/r8169_main.c-1906-\t\tif (speed == SPEED_1000) {\n--\ndrivers/net/ethernet/realtek/r8169_main.c-1916-\t\trtl_reset_packet_filter(tp);\ndrivers/net/ethernet/realtek/r8169_main.c:1917:\t} else if (tp-\u003emac_version == RTL_GIGA_MAC_VER_35 ||\ndrivers/net/ethernet/realtek/r8169_main.c:1918:\t\t tp-\u003emac_version == RTL_GIGA_MAC_VER_36) {\ndrivers/net/ethernet/realtek/r8169_main.c-1919-\t\tif (speed == SPEED_1000) {\n--\ndrivers/net/ethernet/realtek/r8169_main.c-1925-\t\t}\ndrivers/net/ethernet/realtek/r8169_main.c:1926:\t} else if (tp-\u003emac_version == RTL_GIGA_MAC_VER_37) {\ndrivers/net/ethernet/realtek/r8169_main.c-1927-\t\tif (speed == SPEED_10) {\n--\ndrivers/net/ethernet/realtek/r8169_main.c=1946=static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts)\n--\ndrivers/net/ethernet/realtek/r8169_main.c-1974-\tswitch (tp-\u003emac_version) {\ndrivers/net/ethernet/realtek/r8169_main.c:1975:\tcase RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06:\ndrivers/net/ethernet/realtek/r8169_main.c-1976-\t\tr8169_mod_reg8_cond(tp, Config1, PMEnable, wolopts);\ndrivers/net/ethernet/realtek/r8169_main.c-1977-\t\tbreak;\ndrivers/net/ethernet/realtek/r8169_main.c:1978:\tcase RTL_GIGA_MAC_VER_34:\ndrivers/net/ethernet/realtek/r8169_main.c:1979:\tcase RTL_GIGA_MAC_VER_37:\ndrivers/net/ethernet/realtek/r8169_main.c:1980:\tcase RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_LAST:\ndrivers/net/ethernet/realtek/r8169_main.c-1981-\t\tr8169_mod_reg8_cond(tp, Config2, PME_SIGNAL, wolopts);\n--\ndrivers/net/ethernet/realtek/r8169_main.c=2028=static netdev_features_t rtl8169_fix_features(struct net_device *dev,\n--\ndrivers/net/ethernet/realtek/r8169_main.c-2036-\tif (dev-\u003emtu \u003e ETH_DATA_LEN \u0026\u0026\ndrivers/net/ethernet/realtek/r8169_main.c:2037:\t tp-\u003emac_version \u003e RTL_GIGA_MAC_VER_06)\ndrivers/net/ethernet/realtek/r8169_main.c-2038-\t\tfeatures \u0026= ~(NETIF_F_CSUM_MASK | NETIF_F_ALL_TSO);\n--\ndrivers/net/ethernet/realtek/r8169_main.c=2180=static void rtl8169_init_counter_offsets(struct rtl8169_private *tp)\n--\ndrivers/net/ethernet/realtek/r8169_main.c-2185-\t * rtl8169_init_counter_offsets is called from rtl_open. On chip\ndrivers/net/ethernet/realtek/r8169_main.c:2186:\t * versions prior to RTL_GIGA_MAC_VER_19 the tally counters are only\ndrivers/net/ethernet/realtek/r8169_main.c-2187-\t * reset by a power cycle, while the counter values collected by the\n--\ndrivers/net/ethernet/realtek/r8169_main.c-2201-\ndrivers/net/ethernet/realtek/r8169_main.c:2202:\tif (tp-\u003emac_version \u003e= RTL_GIGA_MAC_VER_19) {\ndrivers/net/ethernet/realtek/r8169_main.c-2203-\t\trtl8169_do_counters(tp, CounterReset);\n--\ndrivers/net/ethernet/realtek/r8169_main.c=2302=rtl_coalesce_info(struct rtl8169_private *tp)\n--\ndrivers/net/ethernet/realtek/r8169_main.c-2305-\ndrivers/net/ethernet/realtek/r8169_main.c:2306:\tif (tp-\u003emac_version \u003c= RTL_GIGA_MAC_VER_06)\ndrivers/net/ethernet/realtek/r8169_main.c-2307-\t\tci = rtl_coalesce_info_8169;\n--\ndrivers/net/ethernet/realtek/r8169_main.c=2453=static void rtl_set_eee_txidle_timer(struct rtl8169_private *tp)\n--\ndrivers/net/ethernet/realtek/r8169_main.c-2457-\tswitch (tp-\u003emac_version) {\ndrivers/net/ethernet/realtek/r8169_main.c:2458:\tcase RTL_GIGA_MAC_VER_46:\ndrivers/net/ethernet/realtek/r8169_main.c:2459:\tcase RTL_GIGA_MAC_VER_48:\ndrivers/net/ethernet/realtek/r8169_main.c-2460-\t\ttp-\u003etx_lpi_timer = timer_val;\n--\ndrivers/net/ethernet/realtek/r8169_main.c-2462-\t\tbreak;\ndrivers/net/ethernet/realtek/r8169_main.c:2463:\tcase RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_LAST:\ndrivers/net/ethernet/realtek/r8169_main.c-2464-\t\ttp-\u003etx_lpi_timer = timer_val;\n--\ndrivers/net/ethernet/realtek/r8169_main.c=2640=static const struct rtl_chip_info *rtl8169_get_chip_version(u32 xid, bool gmii)\n--\ndrivers/net/ethernet/realtek/r8169_main.c-2643-\tstatic const struct rtl_chip_info rtl8106eus_info = {\ndrivers/net/ethernet/realtek/r8169_main.c:2644:\t\t.mac_version = RTL_GIGA_MAC_VER_43,\ndrivers/net/ethernet/realtek/r8169_main.c-2645-\t\t.name = \"RTL8106eus\",\n--\ndrivers/net/ethernet/realtek/r8169_main.c-2648-\tstatic const struct rtl_chip_info rtl8107e_info = {\ndrivers/net/ethernet/realtek/r8169_main.c:2649:\t\t.mac_version = RTL_GIGA_MAC_VER_48,\ndrivers/net/ethernet/realtek/r8169_main.c-2650-\t\t.name = \"RTL8107e\",\n--\ndrivers/net/ethernet/realtek/r8169_main.c-2657-\ndrivers/net/ethernet/realtek/r8169_main.c:2658:\tif (p-\u003emac_version == RTL_GIGA_MAC_VER_42 \u0026\u0026 !gmii)\ndrivers/net/ethernet/realtek/r8169_main.c-2659-\t\treturn \u0026rtl8106eus_info;\ndrivers/net/ethernet/realtek/r8169_main.c:2660:\tif (p-\u003emac_version == RTL_GIGA_MAC_VER_46 \u0026\u0026 !gmii)\ndrivers/net/ethernet/realtek/r8169_main.c-2661-\t\treturn \u0026rtl8107e_info;\n--\ndrivers/net/ethernet/realtek/r8169_main.c=2733=static void rtl8169_init_phy(struct rtl8169_private *tp)\n--\ndrivers/net/ethernet/realtek/r8169_main.c-2738-\ndrivers/net/ethernet/realtek/r8169_main.c:2739:\tif (tp-\u003emac_version \u003c= RTL_GIGA_MAC_VER_06) {\ndrivers/net/ethernet/realtek/r8169_main.c-2740-\t\tpci_write_config_byte(tp-\u003epci_dev, PCI_LATENCY_TIMER, 0x40);\n--\ndrivers/net/ethernet/realtek/r8169_main.c-2745-\ndrivers/net/ethernet/realtek/r8169_main.c:2746:\tif (tp-\u003emac_version == RTL_GIGA_MAC_VER_05 \u0026\u0026\ndrivers/net/ethernet/realtek/r8169_main.c-2747-\t tp-\u003epci_dev-\u003esubsystem_vendor == PCI_VENDOR_ID_GIGABYTE \u0026\u0026\n--\ndrivers/net/ethernet/realtek/r8169_main.c=2757=static void rtl_rar_set(struct rtl8169_private *tp, const u8 *addr)\n--\ndrivers/net/ethernet/realtek/r8169_main.c-2766-\ndrivers/net/ethernet/realtek/r8169_main.c:2767:\tif (tp-\u003emac_version == RTL_GIGA_MAC_VER_34)\ndrivers/net/ethernet/realtek/r8169_main.c-2768-\t\trtl_rar_exgmac_set(tp, addr);\n--\ndrivers/net/ethernet/realtek/r8169_main.c=2787=static void rtl_init_rxcfg(struct rtl8169_private *tp)\n--\ndrivers/net/ethernet/realtek/r8169_main.c-2789-\tswitch (tp-\u003emac_version) {\ndrivers/net/ethernet/realtek/r8169_main.c:2790:\tcase RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06:\ndrivers/net/ethernet/realtek/r8169_main.c:2791:\tcase RTL_GIGA_MAC_VER_10 ... RTL_GIGA_MAC_VER_17:\ndrivers/net/ethernet/realtek/r8169_main.c-2792-\t\tRTL_W32(tp, RxConfig, RX_FIFO_THRESH | RX_DMA_BURST);\ndrivers/net/ethernet/realtek/r8169_main.c-2793-\t\tbreak;\ndrivers/net/ethernet/realtek/r8169_main.c:2794:\tcase RTL_GIGA_MAC_VER_18 ... RTL_GIGA_MAC_VER_24:\ndrivers/net/ethernet/realtek/r8169_main.c:2795:\tcase RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_36:\ndrivers/net/ethernet/realtek/r8169_main.c:2796:\tcase RTL_GIGA_MAC_VER_38:\ndrivers/net/ethernet/realtek/r8169_main.c-2797-\t\tRTL_W32(tp, RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST);\ndrivers/net/ethernet/realtek/r8169_main.c-2798-\t\tbreak;\ndrivers/net/ethernet/realtek/r8169_main.c:2799:\tcase RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_52:\ndrivers/net/ethernet/realtek/r8169_main.c-2800-\t\tRTL_W32(tp, RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST | RX_EARLY_OFF);\ndrivers/net/ethernet/realtek/r8169_main.c-2801-\t\tbreak;\ndrivers/net/ethernet/realtek/r8169_main.c:2802:\tcase RTL_GIGA_MAC_VER_61:\ndrivers/net/ethernet/realtek/r8169_main.c-2803-\t\tRTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST);\ndrivers/net/ethernet/realtek/r8169_main.c-2804-\t\tbreak;\ndrivers/net/ethernet/realtek/r8169_main.c:2805:\tcase RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_LAST:\ndrivers/net/ethernet/realtek/r8169_main.c-2806-\t\tRTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST |\n--\ndrivers/net/ethernet/realtek/r8169_main.c=2836=static void rtl_jumbo_config(struct rtl8169_private *tp)\n--\ndrivers/net/ethernet/realtek/r8169_main.c-2840-\ndrivers/net/ethernet/realtek/r8169_main.c:2841:\tif (jumbo \u0026\u0026 tp-\u003emac_version \u003e= RTL_GIGA_MAC_VER_17 \u0026\u0026\ndrivers/net/ethernet/realtek/r8169_main.c:2842:\t tp-\u003emac_version \u003c= RTL_GIGA_MAC_VER_26)\ndrivers/net/ethernet/realtek/r8169_main.c-2843-\t\treadrq = 512;\n--\ndrivers/net/ethernet/realtek/r8169_main.c-2846-\tswitch (tp-\u003emac_version) {\ndrivers/net/ethernet/realtek/r8169_main.c:2847:\tcase RTL_GIGA_MAC_VER_17:\ndrivers/net/ethernet/realtek/r8169_main.c-2848-\t\tr8169_mod_reg8_cond(tp, Config4, BIT(0), jumbo);\ndrivers/net/ethernet/realtek/r8169_main.c-2849-\t\tbreak;\ndrivers/net/ethernet/realtek/r8169_main.c:2850:\tcase RTL_GIGA_MAC_VER_18 ... RTL_GIGA_MAC_VER_26:\ndrivers/net/ethernet/realtek/r8169_main.c-2851-\t\tr8169_mod_reg8_cond(tp, Config3, Jumbo_En0, jumbo);\n--\ndrivers/net/ethernet/realtek/r8169_main.c-2853-\t\tbreak;\ndrivers/net/ethernet/realtek/r8169_main.c:2854:\tcase RTL_GIGA_MAC_VER_28:\ndrivers/net/ethernet/realtek/r8169_main.c-2855-\t\tr8169_mod_reg8_cond(tp, Config3, Jumbo_En0, jumbo);\ndrivers/net/ethernet/realtek/r8169_main.c-2856-\t\tbreak;\ndrivers/net/ethernet/realtek/r8169_main.c:2857:\tcase RTL_GIGA_MAC_VER_31 ... RTL_GIGA_MAC_VER_33:\ndrivers/net/ethernet/realtek/r8169_main.c-2858-\t\tRTL_W8(tp, MaxTxPacketSize, jumbo ? 0x24 : 0x3f);\n--\ndrivers/net/ethernet/realtek/r8169_main.c=2891=static void rtl_setup_rx_params(struct rtl8169_private *tp)\n--\ndrivers/net/ethernet/realtek/r8169_main.c-2894-\tswitch (tp-\u003emac_version) {\ndrivers/net/ethernet/realtek/r8169_main.c:2895:\tcase RTL_GIGA_MAC_VER_80:\ndrivers/net/ethernet/realtek/r8169_main.c-2896-\t\ttp-\u003ehw_supp_num_rx_queues = R8169_MAX_RX_QUEUES;\n--\ndrivers/net/ethernet/realtek/r8169_main.c=2957=static void rtl_wait_txrx_fifo_empty(struct rtl8169_private *tp)\n--\ndrivers/net/ethernet/realtek/r8169_main.c-2959-\tswitch (tp-\u003emac_version) {\ndrivers/net/ethernet/realtek/r8169_main.c:2960:\tcase RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_52:\ndrivers/net/ethernet/realtek/r8169_main.c-2961-\t\trtl_loop_wait_high(tp, \u0026rtl_txcfg_empty_cond, 100, 42);\n--\ndrivers/net/ethernet/realtek/r8169_main.c-2963-\t\tbreak;\ndrivers/net/ethernet/realtek/r8169_main.c:2964:\tcase RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_61:\ndrivers/net/ethernet/realtek/r8169_main.c-2965-\t\trtl_loop_wait_high(tp, \u0026rtl_rxtx_empty_cond, 100, 42);\ndrivers/net/ethernet/realtek/r8169_main.c-2966-\t\tbreak;\ndrivers/net/ethernet/realtek/r8169_main.c:2967:\tcase RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_LAST:\ndrivers/net/ethernet/realtek/r8169_main.c-2968-\t\tRTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq);\n--\ndrivers/net/ethernet/realtek/r8169_main.c=2989=static void rtl_wol_enable_rx(struct rtl8169_private *tp)\ndrivers/net/ethernet/realtek/r8169_main.c-2990-{\ndrivers/net/ethernet/realtek/r8169_main.c:2991:\tif (tp-\u003emac_version \u003e= RTL_GIGA_MAC_VER_25)\ndrivers/net/ethernet/realtek/r8169_main.c-2992-\t\tRTL_W32(tp, RxConfig, RTL_R32(tp, RxConfig) |\n--\ndrivers/net/ethernet/realtek/r8169_main.c-2994-\ndrivers/net/ethernet/realtek/r8169_main.c:2995:\tif (tp-\u003emac_version \u003e= RTL_GIGA_MAC_VER_40)\ndrivers/net/ethernet/realtek/r8169_main.c-2996-\t\trtl_disable_rxdvgate(tp);\n--\ndrivers/net/ethernet/realtek/r8169_main.c=2999=static void rtl_prepare_power_down(struct rtl8169_private *tp)\ndrivers/net/ethernet/realtek/r8169_main.c-3000-{\ndrivers/net/ethernet/realtek/r8169_main.c:3001:\tif (tp-\u003emac_version == RTL_GIGA_MAC_VER_32 ||\ndrivers/net/ethernet/realtek/r8169_main.c:3002:\t tp-\u003emac_version == RTL_GIGA_MAC_VER_33)\ndrivers/net/ethernet/realtek/r8169_main.c-3003-\t\trtl_ephy_write(tp, 0x19, 0xff64);\n--\ndrivers/net/ethernet/realtek/r8169_main.c=3105=static void rtl8169_set_magic_reg(struct rtl8169_private *tp)\n--\ndrivers/net/ethernet/realtek/r8169_main.c-3108-\ndrivers/net/ethernet/realtek/r8169_main.c:3109:\tif (tp-\u003emac_version == RTL_GIGA_MAC_VER_05)\ndrivers/net/ethernet/realtek/r8169_main.c-3110-\t\tval = 0x000fff00;\ndrivers/net/ethernet/realtek/r8169_main.c:3111:\telse if (tp-\u003emac_version == RTL_GIGA_MAC_VER_06)\ndrivers/net/ethernet/realtek/r8169_main.c-3112-\t\tval = 0x00ffff00;\n--\ndrivers/net/ethernet/realtek/r8169_main.c=3132=static void rtl_set_rx_mode(struct net_device *dev)\n--\ndrivers/net/ethernet/realtek/r8169_main.c-3144-\t} else if (dev-\u003eflags \u0026 IFF_ALLMULTI ||\ndrivers/net/ethernet/realtek/r8169_main.c:3145:\t\t tp-\u003emac_version == RTL_GIGA_MAC_VER_35) {\ndrivers/net/ethernet/realtek/r8169_main.c-3146-\t\t/* accept all multicasts */\n--\ndrivers/net/ethernet/realtek/r8169_main.c-3157-\ndrivers/net/ethernet/realtek/r8169_main.c:3158:\t\tif (tp-\u003emac_version \u003e RTL_GIGA_MAC_VER_06) {\ndrivers/net/ethernet/realtek/r8169_main.c-3159-\t\t\ttmp = mc_filter[0];\n--\ndrivers/net/ethernet/realtek/r8169_main.c=3296=static void rtl_enable_exit_l1(struct rtl8169_private *tp)\n--\ndrivers/net/ethernet/realtek/r8169_main.c-3306-\tswitch (tp-\u003emac_version) {\ndrivers/net/ethernet/realtek/r8169_main.c:3307:\tcase RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_36:\ndrivers/net/ethernet/realtek/r8169_main.c-3308-\t\trtl_eri_set_bits(tp, 0xd4, 0x1f00);\ndrivers/net/ethernet/realtek/r8169_main.c-3309-\t\tbreak;\ndrivers/net/ethernet/realtek/r8169_main.c:3310:\tcase RTL_GIGA_MAC_VER_37 ... RTL_GIGA_MAC_VER_38:\ndrivers/net/ethernet/realtek/r8169_main.c-3311-\t\trtl_eri_set_bits(tp, 0xd4, 0x0c00);\ndrivers/net/ethernet/realtek/r8169_main.c-3312-\t\tbreak;\ndrivers/net/ethernet/realtek/r8169_main.c:3313:\tcase RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_LAST:\ndrivers/net/ethernet/realtek/r8169_main.c-3314-\t\tr8168_mac_ocp_modify(tp, 0xc0ac, 0, 0x1f80);\n--\ndrivers/net/ethernet/realtek/r8169_main.c=3321=static void rtl_disable_exit_l1(struct rtl8169_private *tp)\n--\ndrivers/net/ethernet/realtek/r8169_main.c-3323-\tswitch (tp-\u003emac_version) {\ndrivers/net/ethernet/realtek/r8169_main.c:3324:\tcase RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_38:\ndrivers/net/ethernet/realtek/r8169_main.c-3325-\t\trtl_eri_clear_bits(tp, 0xd4, 0x1f00);\ndrivers/net/ethernet/realtek/r8169_main.c-3326-\t\tbreak;\ndrivers/net/ethernet/realtek/r8169_main.c:3327:\tcase RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_LAST:\ndrivers/net/ethernet/realtek/r8169_main.c-3328-\t\tr8168_mac_ocp_modify(tp, 0xc0ac, 0x1f80, 0);\n--\ndrivers/net/ethernet/realtek/r8169_main.c=3335=static void rtl_enable_ltr(struct rtl8169_private *tp)\n--\ndrivers/net/ethernet/realtek/r8169_main.c-3337-\tswitch (tp-\u003emac_version) {\ndrivers/net/ethernet/realtek/r8169_main.c:3338:\tcase RTL_GIGA_MAC_VER_80:\ndrivers/net/ethernet/realtek/r8169_main.c-3339-\t\tr8168_mac_ocp_write(tp, 0xcdd0, 0x9003);\n--\ndrivers/net/ethernet/realtek/r8169_main.c-3359-\t\tbreak;\ndrivers/net/ethernet/realtek/r8169_main.c:3360:\tcase RTL_GIGA_MAC_VER_70:\ndrivers/net/ethernet/realtek/r8169_main.c-3361-\t\tr8168_mac_ocp_write(tp, 0xcdd0, 0x9003);\n--\ndrivers/net/ethernet/realtek/r8169_main.c-3379-\t\tbreak;\ndrivers/net/ethernet/realtek/r8169_main.c:3380:\tcase RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_66:\ndrivers/net/ethernet/realtek/r8169_main.c-3381-\t\tr8168_mac_ocp_write(tp, 0xcdd0, 0x9003);\n--\ndrivers/net/ethernet/realtek/r8169_main.c-3397-\t\tbreak;\ndrivers/net/ethernet/realtek/r8169_main.c:3398:\tcase RTL_GIGA_MAC_VER_52:\ndrivers/net/ethernet/realtek/r8169_main.c-3399-\t\tr8168_mac_ocp_write(tp, 0xcdd0, 0x9003);\n--\ndrivers/net/ethernet/realtek/r8169_main.c-3413-\t\tbreak;\ndrivers/net/ethernet/realtek/r8169_main.c:3414:\tcase RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48:\ndrivers/net/ethernet/realtek/r8169_main.c-3415-\t\tr8168_mac_ocp_modify(tp, ALDPS_LTR, 0x0000, ALDPS_LTR_EN);\n--\ndrivers/net/ethernet/realtek/r8169_main.c-3417-\t\tfallthrough;\ndrivers/net/ethernet/realtek/r8169_main.c:3418:\tcase RTL_GIGA_MAC_VER_51:\ndrivers/net/ethernet/realtek/r8169_main.c-3419-\t\tr8168_mac_ocp_modify(tp, LTR_SNOOP, 0x0000, LTR_SNOOP_EN);\n--\ndrivers/net/ethernet/realtek/r8169_main.c=3437=static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable)\n--\ndrivers/net/ethernet/realtek/r8169_main.c-3440-\ndrivers/net/ethernet/realtek/r8169_main.c:3441:\tif (tp-\u003emac_version \u003c RTL_GIGA_MAC_VER_32)\ndrivers/net/ethernet/realtek/r8169_main.c-3442-\t\treturn;\n--\ndrivers/net/ethernet/realtek/r8169_main.c-3448-\t\t */\ndrivers/net/ethernet/realtek/r8169_main.c:3449:\t\tif (tp-\u003emac_version == RTL_GIGA_MAC_VER_42 ||\ndrivers/net/ethernet/realtek/r8169_main.c:3450:\t\t tp-\u003emac_version == RTL_GIGA_MAC_VER_43)\ndrivers/net/ethernet/realtek/r8169_main.c-3451-\t\t\treturn;\n--\ndrivers/net/ethernet/realtek/r8169_main.c-3454-\t\tswitch (tp-\u003emac_version) {\ndrivers/net/ethernet/realtek/r8169_main.c:3455:\t\tcase RTL_GIGA_MAC_VER_70:\ndrivers/net/ethernet/realtek/r8169_main.c:3456:\t\tcase RTL_GIGA_MAC_VER_80:\ndrivers/net/ethernet/realtek/r8169_main.c-3457-\t\t\tval8 = RTL_R8(tp, INT_CFG0_8125) | INT_CFG0_CLKREQEN;\n--\ndrivers/net/ethernet/realtek/r8169_main.c-3466-\t\tswitch (tp-\u003emac_version) {\ndrivers/net/ethernet/realtek/r8169_main.c:3467:\t\tcase RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48:\ndrivers/net/ethernet/realtek/r8169_main.c:3468:\t\tcase RTL_GIGA_MAC_VER_52:\ndrivers/net/ethernet/realtek/r8169_main.c:3469:\t\tcase RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_LAST:\ndrivers/net/ethernet/realtek/r8169_main.c-3470-\t\t\t/* reset ephy tx/rx disable timer */\n--\ndrivers/net/ethernet/realtek/r8169_main.c-3479-\t\tswitch (tp-\u003emac_version) {\ndrivers/net/ethernet/realtek/r8169_main.c:3480:\t\tcase RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48:\ndrivers/net/ethernet/realtek/r8169_main.c:3481:\t\tcase RTL_GIGA_MAC_VER_52:\ndrivers/net/ethernet/realtek/r8169_main.c:3482:\t\tcase RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_LAST:\ndrivers/net/ethernet/realtek/r8169_main.c-3483-\t\t\tr8168_mac_ocp_modify(tp, 0xe092, 0x00ff, 0);\n--\ndrivers/net/ethernet/realtek/r8169_main.c-3489-\t\tswitch (tp-\u003emac_version) {\ndrivers/net/ethernet/realtek/r8169_main.c:3490:\t\tcase RTL_GIGA_MAC_VER_70:\ndrivers/net/ethernet/realtek/r8169_main.c:3491:\t\tcase RTL_GIGA_MAC_VER_80:\ndrivers/net/ethernet/realtek/r8169_main.c-3492-\t\t\tval8 = RTL_R8(tp, INT_CFG0_8125) \u0026 ~INT_CFG0_CLKREQEN;\n--\ndrivers/net/ethernet/realtek/r8169_main.c=4234=static void rtl_hw_start_8125_common(struct rtl8169_private *tp)\n--\ndrivers/net/ethernet/realtek/r8169_main.c-4259-\ndrivers/net/ethernet/realtek/r8169_main.c:4260:\tif (tp-\u003emac_version == RTL_GIGA_MAC_VER_70 ||\ndrivers/net/ethernet/realtek/r8169_main.c:4261:\t tp-\u003emac_version == RTL_GIGA_MAC_VER_80)\ndrivers/net/ethernet/realtek/r8169_main.c-4262-\t\tRTL_W8(tp, 0xD8, RTL_R8(tp, 0xD8) \u0026 ~0x02);\n--\ndrivers/net/ethernet/realtek/r8169_main.c-4270-\ndrivers/net/ethernet/realtek/r8169_main.c:4271:\tif (tp-\u003emac_version == RTL_GIGA_MAC_VER_80)\ndrivers/net/ethernet/realtek/r8169_main.c-4272-\t\tr8168_mac_ocp_modify(tp, 0xe614, 0x0f00, 0x0f00);\ndrivers/net/ethernet/realtek/r8169_main.c:4273:\telse if (tp-\u003emac_version == RTL_GIGA_MAC_VER_70)\ndrivers/net/ethernet/realtek/r8169_main.c-4274-\t\tr8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0400);\ndrivers/net/ethernet/realtek/r8169_main.c:4275:\telse if (tp-\u003emac_version == RTL_GIGA_MAC_VER_63)\ndrivers/net/ethernet/realtek/r8169_main.c-4276-\t\tr8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0200);\n--\ndrivers/net/ethernet/realtek/r8169_main.c-4279-\ndrivers/net/ethernet/realtek/r8169_main.c:4280:\tif (tp-\u003emac_version == RTL_GIGA_MAC_VER_63)\ndrivers/net/ethernet/realtek/r8169_main.c-4281-\t\tr8168_mac_ocp_modify(tp, 0xe63e, 0x0c30, 0x0000);\n--\ndrivers/net/ethernet/realtek/r8169_main.c-4290-\tr8168_mac_ocp_modify(tp, 0xea1c, 0x0003, 0x0001);\ndrivers/net/ethernet/realtek/r8169_main.c:4291:\tif (tp-\u003emac_version == RTL_GIGA_MAC_VER_70 ||\ndrivers/net/ethernet/realtek/r8169_main.c:4292:\t tp-\u003emac_version == RTL_GIGA_MAC_VER_80)\ndrivers/net/ethernet/realtek/r8169_main.c-4293-\t\tr8168_mac_ocp_modify(tp, 0xea1c, 0x0300, 0x0000);\n--\n\n"
} |
| 5/2 | 2026/09/29 07:21 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 45520 output: 49 thoughts: 21 Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience: **Analyzing r8169_pci_driver's PCI ID Handling** Alright, let's get down to brass tacks. I need to quickly ascertain the scope of `r8169_pci_driver`. Specifically, I want to drill down and understand precisely which PCI IDs this driver is designed to handle. I know this driver is responsible for Realtek Gigabit Ethernet controllers, but I need a rapid, granular understanding of its supported device coverage. Knowing the exact IDs is crucial for everything from ensuring correct driver association during bring-up and debugging device-specific quirks, to gauging the potential impact of changes or updates to the driver itself. Let's see what that looks like. |
| 6/2 | 2026/09/29 07:21 | tool | grepper |
0mArgs:{
"Expression": "rtl8169_pci_tbl",
"PathPrefix": "drivers/net/ethernet/realtek/r8169_main.c"
}Results: {
"Output": "drivers/net/ethernet/realtek/r8169_main.c=258=static const struct rtl_chip_info rtl_chip_infos_extended[] = {\n--\ndrivers/net/ethernet/realtek/r8169_main.c-265-\ndrivers/net/ethernet/realtek/r8169_main.c:266:static const struct pci_device_id rtl8169_pci_tbl[] = {\ndrivers/net/ethernet/realtek/r8169_main.c-267-\t{ PCI_VDEVICE(REALTEK,\t0x2502) },\n--\ndrivers/net/ethernet/realtek/r8169_main.c-291-\ndrivers/net/ethernet/realtek/r8169_main.c:292:MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl);\ndrivers/net/ethernet/realtek/r8169_main.c-293-\n--\ndrivers/net/ethernet/realtek/r8169_main.c=7062=static struct pci_driver rtl8169_pci_driver = {\ndrivers/net/ethernet/realtek/r8169_main.c-7063-\t.name\t\t= KBUILD_MODNAME,\ndrivers/net/ethernet/realtek/r8169_main.c:7064:\t.id_table\t= rtl8169_pci_tbl,\ndrivers/net/ethernet/realtek/r8169_main.c-7065-\t.probe\t\t= rtl_init_one,\n"
} |
| 7/2 | 2026/09/29 07:21 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 46189 output: 47 thoughts: 34 Thoughts: Okay, let's dive into this. Here's my take on those thoughts: **Analyzing `r8169_main.c` around line 266** Alright, I'm going to take a look at the `r8169_main.c` file, specifically around line 266. My initial hunch is this is the point where the author is asking me to start my analysis. Given that this is the realtek ethernet driver, I'm expecting to find core initialization, packet handling logic, or perhaps interrupt handling code in that vicinity. Without knowing the exact function or block of code, I'll need to assess the surrounding context. I'll need to quickly identify the function the line belongs to, what variables are being used, and what's the purpose of the code. This will allow me to build a framework for a deeper diagnosis. From this line I'll be looking to start my evaluation. |
| 8/2 | 2026/09/29 07:21 | tool | read-file |
0mArgs:{
"File": "drivers/net/ethernet/realtek/r8169_main.c",
"FirstLine": 265,
"LineCount": 35
}Results: {
"Contents": " 265:\t\n 266:\tstatic const struct pci_device_id rtl8169_pci_tbl[] = {\n 267:\t\t{ PCI_VDEVICE(REALTEK,\t0x2502) },\n 268:\t\t{ PCI_VDEVICE(REALTEK,\t0x2600) },\n 269:\t\t{ PCI_VDEVICE(REALTEK,\t0x8129) },\n 270:\t\t{ PCI_VDEVICE(REALTEK,\t0x8136), .driver_data = RTL_CFG_NO_GBIT },\n 271:\t\t{ PCI_VDEVICE(REALTEK,\t0x8161) },\n 272:\t\t{ PCI_VDEVICE(REALTEK,\t0x8162) },\n 273:\t\t{ PCI_VDEVICE(REALTEK,\t0x8167) },\n 274:\t\t{ PCI_VDEVICE(REALTEK,\t0x8168) },\n 275:\t\t{ PCI_VDEVICE(NCUBE,\t0x8168) },\n 276:\t\t{ PCI_VDEVICE(REALTEK,\t0x8169) },\n 277:\t\t{ PCI_VDEVICE(DLINK,\t0x4300) },\n 278:\t\t{ PCI_VDEVICE(DLINK,\t0x4302) },\n 279:\t\t{ PCI_VDEVICE(AT,\t0xc107) },\n 280:\t\t{ PCI_VDEVICE(USR,\t0x0116) },\n 281:\t\t{ PCI_VDEVICE_SUB(LINKSYS, 0x1032, PCI_ANY_ID, 0x0024) },\n 282:\t\t{ PCI_DEVICE_SUB(0x0001, 0x8168, PCI_ANY_ID, 0x2410) },\n 283:\t\t{ PCI_VDEVICE(REALTEK,\t0x8125) },\n 284:\t\t{ PCI_VDEVICE(REALTEK,\t0x8126) },\n 285:\t\t{ PCI_VDEVICE(REALTEK,\t0x8127) },\n 286:\t\t{ PCI_VDEVICE(REALTEK,\t0x3000) },\n 287:\t\t{ PCI_VDEVICE(REALTEK,\t0x5000) },\n 288:\t\t{ PCI_VDEVICE(REALTEK,\t0x0e10) },\n 289:\t\t{ }\n 290:\t};\n 291:\t\n 292:\tMODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl);\n 293:\t\n 294:\tenum rtl_registers {\n 295:\t\tMAC0\t\t= 0,\t/* Ethernet hardware address. */\n 296:\t\tMAC4\t\t= 4,\n 297:\t\tMAR0\t\t= 8,\t/* Multicast filter. */\n 298:\t\tCounterAddrLow\t\t= 0x10,\n 299:\t\tCounterAddrHigh\t\t= 0x14,\n"
} |
| 9/2 | 2026/09/29 07:21 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 47294 output: 36 thoughts: 546 Thoughts: **My Thought Process: RTL8169 Emulation for Fuzzing** Okay, first things first, can syzkaller or QEMU even *emulate* the RTL8169? I need to figure out if this is even feasible. Does QEMU have the necessary device support? Let's see... looking at the `-net nic,model=?` options, it appears it *does* support various network devices, including rtl8139, but I don't see rtl8169 explicitly listed. Wait, so is it the 8139 or the 8169? Hmm, QEMU has rtl8139... but does it *truly* emulate the 8169? I need to be sure. Then I need to think about syzkaller and its capabilities. Does it have any PCI fuzzing mechanisms, perhaps through sysfs, virtio-pci, or VFIO? This is crucial to reaching the device, if it is supported! Okay, let's step back and consult the guidelines. Specifically, guideline number 2. I need to be *absolutely* sure that the work I'm doing isn't immediately disqualified. Let's review... "WHEN TO RETURN WorthFuzzing=false (NEGATIVE CRITERIA)" – right, *negative criteria*. It mentions "Structurally unreachable hardware". *That* is what I need to watch out for. Specifically: vendor-specific PCIe switches, SmartNICs, GPU drivers (like mlxsw, pds_core, qed, ionic, amdgpu) which require physical cards not emulated in standard QEMU. That's a red flag. Or, drivers that are only invoked through device removal. So, let's see if the RTL8169 falls under this unreachable category. Is the RTL8169 structurally unreachable? Does syzkaller have a way to reach it? Does QEMU *actually* emulate it? I'm going to dig deeper into QEMU's code now. Okay, checking QEMU's `hw/net/rtl8139.c`... It looks like QEMU implements the Realtek RTL8139, with PCI ID 0x10ec:0x8139. And C+ mode. I'll need to double check the Linux kernel to know what driver is used with the 8139. Let's see, grepping in the `drivers/net/ethernet/realtek/` directory should tell me which driver is used for 0x8139. |
| 10/2 | 2026/09/29 07:22 | tool | grepper |
0mArgs:{
"Expression": "0x8139",
"PathPrefix": "drivers/net/ethernet/realtek/"
}Results: {
"Output": "drivers/net/ethernet/realtek/8139too.c=237=static const struct pci_device_id rtl8139_pci_tbl[] = {\ndrivers/net/ethernet/realtek/8139too.c:238:\t{ PCI_DEVICE(0x10ec, 0x8139), .driver_data = RTL8139 },\ndrivers/net/ethernet/realtek/8139too.c-239-\t{ PCI_DEVICE(0x10ec, 0x8138), .driver_data = RTL8139 },\n--\ndrivers/net/ethernet/realtek/8139too.c-254-\t{ PCI_DEVICE(0x126c, 0x1211), .driver_data = RTL8139 },\ndrivers/net/ethernet/realtek/8139too.c:255:\t{ PCI_DEVICE(0x1743, 0x8139), .driver_data = RTL8139 },\ndrivers/net/ethernet/realtek/8139too.c:256:\t{ PCI_DEVICE(0x021b, 0x8139), .driver_data = RTL8139 },\ndrivers/net/ethernet/realtek/8139too.c-257-\t{ PCI_DEVICE(0x16ec, 0xab06), .driver_data = RTL8139 },\n--\ndrivers/net/ethernet/realtek/8139too.c-270-\t */\ndrivers/net/ethernet/realtek/8139too.c:271:\t{ PCI_DEVICE_SUB(PCI_ANY_ID, 0x8139, 0x10ec, 0x8139), .driver_data = RTL8139 },\ndrivers/net/ethernet/realtek/8139too.c:272:\t{ PCI_DEVICE_SUB(PCI_ANY_ID, 0x8139, 0x1186, 0x1300), .driver_data = RTL8139 },\ndrivers/net/ethernet/realtek/8139too.c:273:\t{ PCI_DEVICE_SUB(PCI_ANY_ID, 0x8139, 0x13d1, 0xab06), .driver_data = RTL8139 },\ndrivers/net/ethernet/realtek/8139too.c-274-\n"
} |
| 11/2 | 2026/09/29 07:22 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 49087 output: 43 thoughts: 21 Thoughts: Okay, here's the summary, rendered as if I am the expert thinking these thoughts: **Analyzing the Binding of 8139cp.c** Alright, let's see, the code snippet highlights the binding of `8139cp.c` to the address `0x8139`. This suggests a specific relationship is being defined. This usually indicates a direct memory mapping, a specific register allocation, or potentially a kernel symbol assignment if we're dealing with device driver level code. My initial thought is to cross-reference this with the kernel's memory map or symbol table to determine exactly what `8139cp.c` is being linked to, and why. Understanding the context of this binding will be critical. Is it a function pointer, a data structure, or something else entirely that's now tied to this address? I need more context to be certain of its significance, but this is definitely a key piece of the puzzle. The goal is likely to interface with the hardware directly. |
| 12/2 | 2026/09/29 07:22 | tool | grepper |
0mError:no matches Args: {
"Expression": "0x8139",
"PathPrefix": "drivers/net/ethernet/realtek/8139cp.c"
}Results: {
"error": "no matches"
} |
| 13/2 | 2026/09/29 07:22 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 49380 output: 41 thoughts: 17 Thoughts: Okay, let's dive into this. Here's how I'd approach that snippet, considering my expertise: **Checking the PCI Table in `8139cp.c`** Alright, time to get my hands dirty. My immediate thought is, "Let's crack open `8139cp.c` and specifically examine its PCI table." I'm not just idly browsing; I'm going directly to the source. The PCI table is critical for any driver handling a PCI-based device like the RTL8139. I'm looking for the essential configuration information that defines how the driver interacts with the hardware. I want to check how the driver identifies and initializes the RTL8139 PCI device. I'll be scrutinizing the entries within this table, paying close attention to the Vendor ID, Device ID, Subsystem ID, and Subsystem Vendor ID. These identifiers are the keys that the driver uses to correctly recognize and bind to the correct hardware. I'll also be searching for any interrupt settings, resource allocation details, or any other specific configurations defined in the table. I'll be looking to see if the table entries are well-structured, if they are comprehensive, and how they relate to the overall PCI enumeration process. Essentially, I'm digging into the heart of the driver's device recognition strategy to ensure everything's properly defined. |
| 14/2 | 2026/09/29 07:22 | tool | grepper |
0mArgs:{
"Expression": "pci_tbl",
"PathPrefix": "drivers/net/ethernet/realtek/8139cp.c"
}Results: {
"Output": "drivers/net/ethernet/realtek/8139cp.c=2078=static int __maybe_unused cp_resume(struct device *device)\n--\ndrivers/net/ethernet/realtek/8139cp.c-2103-\ndrivers/net/ethernet/realtek/8139cp.c:2104:static const struct pci_device_id cp_pci_tbl[] = {\ndrivers/net/ethernet/realtek/8139cp.c-2105- { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139), },\n--\ndrivers/net/ethernet/realtek/8139cp.c-2108-};\ndrivers/net/ethernet/realtek/8139cp.c:2109:MODULE_DEVICE_TABLE(pci, cp_pci_tbl);\ndrivers/net/ethernet/realtek/8139cp.c-2110-\n--\ndrivers/net/ethernet/realtek/8139cp.c=2113=static struct pci_driver cp_driver = {\ndrivers/net/ethernet/realtek/8139cp.c-2114-\t.name = DRV_NAME,\ndrivers/net/ethernet/realtek/8139cp.c:2115:\t.id_table = cp_pci_tbl,\ndrivers/net/ethernet/realtek/8139cp.c-2116-\t.probe =\tcp_init_one,\n"
} |
| 15/2 | 2026/09/29 07:22 | llm | patch-evaluator |
2mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 50141 output: 171 thoughts: 3473 Thoughts: **Analysis of Fuzzing Potential for Realtek r8169 Driver Patch** Alright, let's break this down. First, it's immediately clear that we're dealing with the Realtek r8169 driver, specifically the `r8169_main.c` file. The patch focuses on adding RSS, multi-queue, and MSI-X support, with particular attention to the RTL8127 (RTL_GIGA_MAC_VER_80) hardware, which is a newer, 10Gbps or multi-gigabit Realtek PCIe NIC. The code touches include the addition of new functions: `rtl_hw_support_rss`, `rtl_setup_rx_params`, `get_max_irq_nvecs` and `get_min_irq_nvecs` which are specific for RTL8127 hardware. My concern is whether this is fuzzable. The core of the problem lies in the reachability of this code in a standard fuzzing setup, like QEMU or a GCE environment. We know that Realtek 8139 is in QEMU, and there's a specific driver for the 8139 family in `8139too.c` and `8139cp.c`. But `r8169` handles the 8169/8168/8125/8127 families – and that's the rub. After checking QEMU documentation and knowledge base, it's confirmed: QEMU *does not* emulate any of these. QEMU only emulates rtl8139, which is handled by different drivers. And GCE uses gVNIC or virtio-net, not Realtek PCIe cards. I checked the PCI device table, `rtl8169_pci_tbl`, and it is conclusive: the 8139 family is not listed in it. Thus, the 8139 family is *not* the same as r8169. Also, all this added RSS and multi-queue code is specifically targeted at RTL8127A, which requires a new device ID and hardware support not found in the standard emulated environments. For any r8169 driver, these new functions would not be used if the mac version is not `RTL_GIGA_MAC_VER_80`. The driver `r8169` *requires* a PCI device with the Realtek vendor ID and the corresponding device ID (0x8168, 0x8169, 0x8125, or 0x8127). The driver registration uses `module_pci_driver(rtl8169_pci_driver)`. Unless that specific hardware is present, the initialization code `rtl_init_one` will never be called, and the network device will not be registered, the functions will not be executed. Since this hardware is not emulated in standard QEMU or GCE setups, then the fuzzing will be impossible. The core triage philosophy states: any code that depends on "structurally unreachable hardware" – such as vendor-specific PCIe NICs not emulated in QEMU – should *not* be considered for fuzzing. This patch definitely fits that category. Therefore, based on the current configuration, it's not possible to fuzz. Based on the schema, since `WorthFuzzing` is `false`, the values for `EnableConfigs` and `FocusSymbols` must be empty, or `null`. The reasoning needs to be short. So, in summary: I will set `WorthFuzzing` to `false` and `FocusSymbols` and `EnableConfigs` to `null` and provide a concise explanation, along the lines of: "The patch modifies the Realtek r8169 Ethernet driver (specifically adding multi-queue RSS and MSI-X support for RTL8127 chips). Realtek r8169/r8125/r8127 devices require physical PCIe hardware not emulated in standard QEMU or virtualized fuzzing environments (QEMU only emulates the older RTL8139 device handled by 8139too/8139cp). As a result, the modified code is structurally unreachable during fuzzing." |
| 16/2 | 2026/09/29 07:25 | tool | set-results |
0mArgs:{
"EnableConfigs": [],
"FocusSymbols": [],
"Reasoning": "The patch modifies the Realtek r8169 Ethernet driver (drivers/net/ethernet/realtek/r8169_main.c) to add multi-queue RSS and MSI-X support for RTL8127 PCIe NICs. Realtek r8169/r8125/r8127 devices require physical PCIe hardware that is not emulated in standard QEMU or virtualized fuzzing environments (QEMU only emulates the legacy RTL8139 device handled by 8139cp/8139too). Therefore, the modified driver code is structurally unreachable in standard fuzzing environments.",
"WorthFuzzing": false
}Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch modifies the Realtek r8169 Ethernet driver (drivers/net/ethernet/realtek/r8169_main.c) to add multi-queue RSS and MSI-X support for RTL8127 PCIe NICs. Realtek r8169/r8125/r8127 devices require physical PCIe hardware that is not emulated in standard QEMU or virtualized fuzzing environments (QEMU only emulates the legacy RTL8139 device handled by 8139cp/8139too). Therefore, the modified driver code is structurally unreachable in standard fuzzing environments.",
"WorthFuzzing": false
} |
| 17/1 | 2026/09/29 07:25 | action | If |
0mArgs:{
"WorthFuzzing": false
}Results: null |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|