lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-ID: <7ea34300-7d55-4411-8ce9-fcc769e05647@gmail.com>
Date: Sun, 12 May 2024 23:06:51 +0100
From: Ken Milmore <ken.milmore@...il.com>
To: netdev@...r.kernel.org
Cc: Heiner Kallweit <hkallweit1@...il.com>, nic_swsd@...ltek.com
Subject: r8169: RTL8125 timer experimentation

I have been experimenting with the "interrupt moderation" timer on the RTL8125, based largely on reading the NetBSD "rge" driver source.
This doesn't seem like much of an improvement over a software timer, but the BSD driver as well as the Realtek-supplied r8125 driver both make use of it.

Despite using 32-bit registers it appears that the timer is 16-bit, and runs at 125 MHz.
The default timeout interval used by the aforementioned drivers is 0x2600 which equates to about 78 us.
This interval maybe seems a bit long, but I note that both drivers use a ring buffer size of 1024 vs only 256 in the r8169 driver.

The patch below is just for interest. It modifies r8169 to use the timer when enabling interrupts from rtl8169_poll, following any Tx or Rx work having been done.
The timer interval can be adjusted via a module parameter.



diff --git linux-source-6.1~/drivers/net/ethernet/realtek/r8169_main.c linux-source-6.1/drivers/net/ethernet/realtek/r8169_main.c
index 6e34177..1fc470c 100644
--- linux-source-6.1~/drivers/net/ethernet/realtek/r8169_main.c
+++ linux-source-6.1/drivers/net/ethernet/realtek/r8169_main.c
@@ -329,6 +329,8 @@ enum rtl8168_registers {
 enum rtl8125_registers {
 	IntrMask_8125		= 0x38,
 	IntrStatus_8125		= 0x3c,
+	TimerCnt0_8125		= 0x48,
+	TimerInt0_8125		= 0x58,
 	TxPoll_8125		= 0x90,
 	MAC0_BKP		= 0x19e0,
 	EEE_TXIDLE_TIMER_8125	= 0x6048,
@@ -660,6 +662,9 @@ MODULE_FIRMWARE(FIRMWARE_8107E_2);
 MODULE_FIRMWARE(FIRMWARE_8125A_3);
 MODULE_FIRMWARE(FIRMWARE_8125B_2);
 
+static u16 rtl8125_timer_interval __read_mostly = 0x2600;
+module_param(rtl8125_timer_interval, ushort, 0644);
+
 static inline struct device *tp_to_dev(struct rtl8169_private *tp)
 {
 	return &tp->pci_dev->dev;
@@ -1324,6 +1329,26 @@ u8 rtl8168d_efuse_read(struct rtl8169_private *tp, int reg_addr)
 		RTL_R32(tp, EFUSEAR) & EFUSEAR_DATA_MASK : ~0;
 }
 
+static void rtl8125_hard_irq_enable(struct rtl8169_private *tp)
+{
+	u32 mask = tp->irq_mask & ~PCSTimeout;
+
+	RTL_W32(tp, TimerInt0_8125, 0);
+	RTL_W32(tp, IntrMask_8125, mask);
+}
+
+static void rtl8125_timer_irq_enable(struct rtl8169_private *tp)
+{
+	u16 interval = READ_ONCE(rtl8125_timer_interval);
+
+	if (interval) {
+		RTL_W32(tp, TimerInt0_8125, interval);
+		RTL_W32(tp, TimerCnt0_8125, 1);
+		RTL_W32(tp, IntrMask_8125, PCSTimeout);
+	} else
+		rtl8125_hard_irq_enable(tp);
+}
+
 static u32 rtl_get_events(struct rtl8169_private *tp)
 {
 	if (rtl_is_8125(tp))
@@ -1351,7 +1376,7 @@ static void rtl_irq_disable(struct rtl8169_private *tp)
 static void rtl_irq_enable(struct rtl8169_private *tp)
 {
 	if (rtl_is_8125(tp))
-		RTL_W32(tp, IntrMask_8125, tp->irq_mask);
+		rtl8125_hard_irq_enable(tp);
 	else
 		RTL_W16(tp, IntrMask, tp->irq_mask);
 }
@@ -4430,7 +4455,7 @@ static void rtl8169_pcierr_interrupt(struct net_device *dev)
 	rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
 }
 
-static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp,
+static bool rtl_tx(struct net_device *dev, struct rtl8169_private *tp,
 		   int budget)
 {
 	unsigned int dirty_tx, bytes_compl = 0, pkts_compl = 0;
@@ -4481,6 +4506,9 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp,
 		 */
 		if (READ_ONCE(tp->cur_tx) != dirty_tx && skb)
 			rtl8169_doorbell(tp);
+		return true;
+	} else {
+		return false;
 	}
 }
 
@@ -4654,13 +4682,18 @@ 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;
+	bool tx_done;
 
-	rtl_tx(dev, tp, budget);
+	tx_done = rtl_tx(dev, tp, budget);
 
 	work_done = rtl_rx(dev, tp, budget);
 
-	if (work_done < budget && napi_complete_done(napi, work_done))
-		rtl_irq_enable(tp);
+	if (work_done < budget && napi_complete_done(napi, work_done)) {
+		if (rtl_is_8125(tp) && (work_done || tx_done))
+			rtl8125_timer_irq_enable(tp);
+		else
+			rtl_irq_enable(tp);
+	}
 
 	return work_done;
 }
@@ -5031,6 +5064,9 @@ static void rtl_set_irq_mask(struct rtl8169_private *tp)
 		tp->irq_mask |= RxFIFOOver;
 	else
 		tp->irq_mask |= RxOverflow;
+
+	if (rtl_is_8125(tp))
+		tp->irq_mask |= PCSTimeout;
 }
 
 static int rtl_alloc_irq(struct rtl8169_private *tp)

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ