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