summaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/realtek/r8169_main.c
diff options
context:
space:
mode:
authorHeiner Kallweit <hkallweit1@gmail.com>2020-11-19 21:57:27 +0100
committerJakub Kicinski <kuba@kernel.org>2020-11-20 18:33:55 -0800
commit94d8a98e6235c2ac4d188e21cab6ea4d43c98806 (patch)
tree52f7741b4f75b1d2ccfa8c58a2da01d2eaebc839 /drivers/net/ethernet/realtek/r8169_main.c
parent9e8ac63fe1bc346275b27d5d8016e465402d3c34 (diff)
r8169: reduce number of workaround doorbell rings
Some chip versions have a hw bug resulting in lost door bell rings. To work around this the doorbell is also rung whenever we still have tx descriptors in flight after having cleaned up tx descriptors. These PCI(e) writes come at a cost, therefore let's reduce the number of extra doorbell rings. If skb is NULL then this means: - last cleaned-up descriptor belongs to a skb with at least one fragment and last fragment isn't marked as sent yet - hw is in progress sending the skb, therefore no extra doorbell ring is needed for this skb - once last fragment is marked as transmitted hw will trigger a tx done interrupt and we come here again (with skb != NULL) and ring the doorbell if needed Therefore skip the workaround doorbell ring if skb is NULL. Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com> Link: https://lore.kernel.org/r/0a15a83c-aecf-ab51-8071-b29d9dcd529a@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'drivers/net/ethernet/realtek/r8169_main.c')
-rw-r--r--drivers/net/ethernet/realtek/r8169_main.c7
1 files changed, 5 insertions, 2 deletions
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index 1acf7128c146..7dd643f535c3 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -4356,18 +4356,19 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp,
int budget)
{
unsigned int dirty_tx, bytes_compl = 0, pkts_compl = 0;
+ struct sk_buff *skb;
dirty_tx = tp->dirty_tx;
while (READ_ONCE(tp->cur_tx) != dirty_tx) {
unsigned int entry = dirty_tx % NUM_TX_DESC;
- struct sk_buff *skb = tp->tx_skb[entry].skb;
u32 status;
status = le32_to_cpu(tp->TxDescArray[entry].opts1);
if (status & DescOwn)
break;
+ skb = tp->tx_skb[entry].skb;
rtl8169_unmap_tx_skb(tp, entry);
if (skb) {
@@ -4397,8 +4398,10 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp,
* too close. Let's kick an extra TxPoll request when a burst
* of start_xmit activity is detected (if it is not detected,
* it is slow enough). -- FR
+ * If skb is NULL then we come here again once a tx irq is
+ * triggered after the last fragment is marked transmitted.
*/
- if (tp->cur_tx != dirty_tx)
+ if (tp->cur_tx != dirty_tx && skb)
rtl8169_doorbell(tp);
}
}