]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blobdiff - drivers/net/ethernet/realtek/r8169_main.c
r8169: improve rtl_tx
[mirror_ubuntu-hirsute-kernel.git] / drivers / net / ethernet / realtek / r8169_main.c
index 00f13805c6f753e5f9fedcc82a36f0cdc988c3af..8910e900ec45e8ac9fb21792bfdd5b35cb4e7adb 100644 (file)
@@ -67,7 +67,7 @@
 
 #define R8169_REGS_SIZE                256
 #define R8169_RX_BUF_SIZE      (SZ_16K - 1)
-#define NUM_TX_DESC    64      /* Number of Tx descriptor registers */
+#define NUM_TX_DESC    256     /* Number of Tx descriptor registers */
 #define NUM_RX_DESC    256U    /* 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))
@@ -584,12 +584,6 @@ enum rtl_flag {
        RTL_FLAG_MAX
 };
 
-struct rtl8169_stats {
-       u64                     packets;
-       u64                     bytes;
-       struct u64_stats_sync   syncp;
-};
-
 struct rtl8169_private {
        void __iomem *mmio_addr;        /* memory map physical address */
        struct pci_dev *pci_dev;
@@ -600,8 +594,6 @@ struct rtl8169_private {
        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 rtl8169_stats rx_stats;
-       struct rtl8169_stats tx_stats;
        struct TxDesc *TxDescArray;     /* 256-aligned Tx descriptor ring */
        struct RxDesc *RxDescArray;     /* 256-aligned Rx descriptor ring */
        dma_addr_t TxPhyAddr;
@@ -700,27 +692,6 @@ static bool rtl_supports_eee(struct rtl8169_private *tp)
               tp->mac_version != RTL_GIGA_MAC_VER_39;
 }
 
-static void rtl_get_priv_stats(struct rtl8169_stats *stats,
-                              u64 *pkts, u64 *bytes)
-{
-       unsigned int start;
-
-       do {
-               start = u64_stats_fetch_begin_irq(&stats->syncp);
-               *pkts = stats->packets;
-               *bytes = stats->bytes;
-       } while (u64_stats_fetch_retry_irq(&stats->syncp, start));
-}
-
-static void rtl_inc_priv_stats(struct rtl8169_stats *stats,
-                              u64 pkts, u64 bytes)
-{
-       u64_stats_update_begin(&stats->syncp);
-       stats->packets += pkts;
-       stats->bytes += bytes;
-       u64_stats_update_end(&stats->syncp);
-}
-
 static void rtl_read_mac_from_reg(struct rtl8169_private *tp, u8 *mac, int reg)
 {
        int i;
@@ -4080,9 +4051,17 @@ err_out:
        return -EIO;
 }
 
-static bool rtl_test_hw_pad_bug(struct rtl8169_private *tp, struct sk_buff *skb)
+static bool rtl_test_hw_pad_bug(struct rtl8169_private *tp)
 {
-       return skb->len < ETH_ZLEN && tp->mac_version == RTL_GIGA_MAC_VER_34;
+       switch (tp->mac_version) {
+       case RTL_GIGA_MAC_VER_34:
+       case RTL_GIGA_MAC_VER_60:
+       case RTL_GIGA_MAC_VER_61:
+       case RTL_GIGA_MAC_VER_63:
+               return true;
+       default:
+               return false;
+       }
 }
 
 static void rtl8169_tso_csum_v1(struct sk_buff *skb, u32 *opts)
@@ -4154,8 +4133,9 @@ static bool rtl8169_tso_csum_v2(struct rtl8169_private *tp,
 
                opts[1] |= transport_offset << TCPHO_SHIFT;
        } else {
-               if (unlikely(rtl_test_hw_pad_bug(tp, skb)))
-                       return !eth_skb_pad(skb);
+               if (unlikely(skb->len < ETH_ZLEN && rtl_test_hw_pad_bug(tp)))
+                       /* eth_skb_pad would free the skb on error */
+                       return !__skb_put_padto(skb, ETH_ZLEN, false);
        }
 
        return true;
@@ -4164,7 +4144,8 @@ static bool rtl8169_tso_csum_v2(struct rtl8169_private *tp,
 static bool rtl_tx_slots_avail(struct rtl8169_private *tp,
                               unsigned int nr_frags)
 {
-       unsigned int slots_avail = tp->dirty_tx + NUM_TX_DESC - tp->cur_tx;
+       unsigned int slots_avail = READ_ONCE(tp->dirty_tx) + NUM_TX_DESC
+                                       - READ_ONCE(tp->cur_tx);
 
        /* A skbuff with nr_frags needs nr_frags+1 entries in the tx queue */
        return slots_avail > nr_frags;
@@ -4334,18 +4315,9 @@ static netdev_features_t rtl8169_features_check(struct sk_buff *skb,
                    rtl_chip_supports_csum_v2(tp))
                        features &= ~NETIF_F_ALL_TSO;
        } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
-               if (skb->len < ETH_ZLEN) {
-                       switch (tp->mac_version) {
-                       case RTL_GIGA_MAC_VER_11:
-                       case RTL_GIGA_MAC_VER_12:
-                       case RTL_GIGA_MAC_VER_17:
-                       case RTL_GIGA_MAC_VER_34:
-                               features &= ~NETIF_F_CSUM_MASK;
-                               break;
-                       default:
-                               break;
-                       }
-               }
+               /* work around hw bug on some chip versions */
+               if (skb->len < ETH_ZLEN)
+                       features &= ~NETIF_F_CSUM_MASK;
 
                if (transport_offset > TCPHO_MAX &&
                    rtl_chip_supports_csum_v2(tp))
@@ -4390,12 +4362,11 @@ static void rtl8169_pcierr_interrupt(struct net_device *dev)
 static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp,
                   int budget)
 {
-       unsigned int dirty_tx, tx_left, bytes_compl = 0, pkts_compl = 0;
+       unsigned int dirty_tx, bytes_compl = 0, pkts_compl = 0;
 
        dirty_tx = tp->dirty_tx;
-       smp_rmb();
 
-       for (tx_left = tp->cur_tx - dirty_tx; tx_left > 0; tx_left--) {
+       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;
@@ -4416,10 +4387,8 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp,
 
        if (tp->dirty_tx != dirty_tx) {
                netdev_completed_queue(dev, pkts_compl, bytes_compl);
+               dev_sw_netstats_tx_add(dev, pkts_compl, bytes_compl);
 
-               rtl_inc_priv_stats(&tp->tx_stats, pkts_compl, bytes_compl);
-
-               tp->dirty_tx = dirty_tx;
                /* Sync with rtl8169_start_xmit:
                 * - publish dirty_tx ring index (write barrier)
                 * - refresh cur_tx ring index and queue status (read barrier)
@@ -4427,7 +4396,7 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp,
                 * a racing xmit thread can only have a right view of the
                 * ring status.
                 */
-               smp_mb();
+               smp_store_mb(tp->dirty_tx, dirty_tx);
                if (netif_queue_stopped(dev) &&
                    rtl_tx_slots_avail(tp, MAX_SKB_FRAGS)) {
                        netif_wake_queue(dev);
@@ -4539,7 +4508,7 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, u32 budget
 
                napi_gro_receive(&tp->napi, skb);
 
-               rtl_inc_priv_stats(&tp->rx_stats, 1, pkt_size);
+               dev_sw_netstats_rx_add(dev, pkt_size);
 release_descriptor:
                rtl8169_mark_to_asic(desc);
        }
@@ -4721,6 +4690,7 @@ 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);
@@ -4732,7 +4702,7 @@ static int rtl_open(struct net_device *dev)
        tp->TxDescArray = dma_alloc_coherent(&pdev->dev, R8169_TX_RING_BYTES,
                                             &tp->TxPhyAddr, GFP_KERNEL);
        if (!tp->TxDescArray)
-               goto err_pm_runtime_put;
+               goto out;
 
        tp->RxDescArray = dma_alloc_coherent(&pdev->dev, R8169_RX_RING_BYTES,
                                             &tp->RxPhyAddr, GFP_KERNEL);
@@ -4745,8 +4715,9 @@ 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(pci_irq_vector(pdev, 0), rtl8169_interrupt,
-                            IRQF_SHARED, dev->name, tp);
+                            irqflags, dev->name, tp);
        if (retval < 0)
                goto err_release_fw_2;
 
@@ -4757,9 +4728,9 @@ static int rtl_open(struct net_device *dev)
        rtl8169_up(tp);
        rtl8169_init_counter_offsets(tp);
        netif_start_queue(dev);
-
-       pm_runtime_put_sync(&pdev->dev);
 out:
+       pm_runtime_put_sync(&pdev->dev);
+
        return retval;
 
 err_free_irq:
@@ -4775,8 +4746,6 @@ err_free_tx_0:
        dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray,
                          tp->TxPhyAddr);
        tp->TxDescArray = NULL;
-err_pm_runtime_put:
-       pm_runtime_put_noidle(&pdev->dev);
        goto out;
 }
 
@@ -4790,9 +4759,7 @@ rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
        pm_runtime_get_noresume(&pdev->dev);
 
        netdev_stats_to_stats64(stats, &dev->stats);
-
-       rtl_get_priv_stats(&tp->rx_stats, &stats->rx_packets, &stats->rx_bytes);
-       rtl_get_priv_stats(&tp->tx_stats, &stats->tx_packets, &stats->tx_bytes);
+       dev_fetch_sw_netstats(stats, dev->tstats);
 
        /*
         * Fetch additional counter values missing in stats collected by driver
@@ -5263,6 +5230,11 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        tp->eee_adv = -1;
        tp->ocp_base = OCP_STD_PHY_BASE;
 
+       dev->tstats = devm_netdev_alloc_pcpu_stats(&pdev->dev,
+                                                  struct pcpu_sw_netstats);
+       if (!dev->tstats)
+               return -ENOMEM;
+
        /* Get the *optional* external "ether_clk" used on some boards */
        rc = rtl_get_ether_clk(tp);
        if (rc)
@@ -5340,8 +5312,6 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
 
        INIT_WORK(&tp->wk.work, rtl_task);
-       u64_stats_init(&tp->rx_stats.syncp);
-       u64_stats_init(&tp->tx_stats.syncp);
 
        rtl_init_mac_address(tp);