Francois Romieu <rom...@fr.zoreil.com> :
[...]
> Updated patch is on the way.

Fixed memcpy in patch 0001, moved counters allocation from open() 
to probe(), returned open() to its original state but something is
still wrong: the link does not come up.

Patches attached.

I'll try again tomorrow.

-- 
Ueimor
>From 8f1b87a115f6c340558b95f6a1748ddbf866d95f Mon Sep 17 00:00:00 2001
Message-Id: 
<8f1b87a115f6c340558b95f6a1748ddbf866d95f.1441670158.git.rom...@fr.zoreil.com>
From: Francois Romieu <rom...@fr.zoreil.com>
Date: Sat, 5 Sep 2015 13:26:30 +0200
Subject: [PATCH 1/3] r8169: decouple the counters data and the device private
 area.
X-Organisation: Land of Sunshine Inc.

Signed-off-by: Francois Romieu <rom...@fr.zoreil.com>
---
 drivers/net/ethernet/realtek/r8169.c | 69 ++++++++++++++++++++++--------------
 1 file changed, 42 insertions(+), 27 deletions(-)

diff --git a/drivers/net/ethernet/realtek/r8169.c 
b/drivers/net/ethernet/realtek/r8169.c
index 24dcbe6..ff1b834 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -833,7 +833,7 @@ struct rtl8169_private {
        unsigned features;
 
        struct mii_if_info mii;
-       struct rtl8169_counters counters;
+       struct rtl8169_counters *counters;
        struct rtl8169_tc_offsets tc_offset;
        u32 saved_wolopts;
        u32 opts1_mask;
@@ -2284,7 +2284,7 @@ static bool rtl8169_update_counters(struct net_device 
*dev)
                return false;
 
        if (rtl_udelay_loop_wait_low(tp, &rtl_counters_cond, 10, 1000))
-               memcpy(&tp->counters, counters, sizeof(*counters));
+               memcpy(tp->counters, counters, sizeof(*counters));
        else
                ret = false;
 
@@ -2296,6 +2296,8 @@ static bool rtl8169_update_counters(struct net_device 
*dev)
 static bool rtl8169_init_counter_offsets(struct net_device *dev)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
+       struct rtl8169_counters *counters = tp->counters;
+       struct rtl8169_tc_offsets *offset = &tp->tc_offset;
        bool ret = false;
 
        /*
@@ -2313,7 +2315,7 @@ static bool rtl8169_init_counter_offsets(struct 
net_device *dev)
         * set at open time by rtl_hw_start.
         */
 
-       if (tp->tc_offset.inited)
+       if (offset->inited)
                return true;
 
        /* If both, reset and update fail, propagate to caller. */
@@ -2323,10 +2325,10 @@ static bool rtl8169_init_counter_offsets(struct 
net_device *dev)
        if (rtl8169_update_counters(dev))
                ret = true;
 
-       tp->tc_offset.tx_errors = tp->counters.tx_errors;
-       tp->tc_offset.tx_multi_collision = tp->counters.tx_multi_collision;
-       tp->tc_offset.tx_aborted = tp->counters.tx_aborted;
-       tp->tc_offset.inited = true;
+       offset->tx_errors = counters->tx_errors;
+       offset->tx_multi_collision = counters->tx_multi_collision;
+       offset->tx_aborted = counters->tx_aborted;
+       offset->inited = true;
 
        return ret;
 }
@@ -2335,24 +2337,25 @@ static void rtl8169_get_ethtool_stats(struct net_device 
*dev,
                                      struct ethtool_stats *stats, u64 *data)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
+       struct rtl8169_counters *c = tp->counters;
 
        ASSERT_RTNL();
 
        rtl8169_update_counters(dev);
 
-       data[0] = le64_to_cpu(tp->counters.tx_packets);
-       data[1] = le64_to_cpu(tp->counters.rx_packets);
-       data[2] = le64_to_cpu(tp->counters.tx_errors);
-       data[3] = le32_to_cpu(tp->counters.rx_errors);
-       data[4] = le16_to_cpu(tp->counters.rx_missed);
-       data[5] = le16_to_cpu(tp->counters.align_errors);
-       data[6] = le32_to_cpu(tp->counters.tx_one_collision);
-       data[7] = le32_to_cpu(tp->counters.tx_multi_collision);
-       data[8] = le64_to_cpu(tp->counters.rx_unicast);
-       data[9] = le64_to_cpu(tp->counters.rx_broadcast);
-       data[10] = le32_to_cpu(tp->counters.rx_multicast);
-       data[11] = le16_to_cpu(tp->counters.tx_aborted);
-       data[12] = le16_to_cpu(tp->counters.tx_underun);
+       data[ 0] = le64_to_cpu(c->tx_packets);
+       data[ 1] = le64_to_cpu(c->rx_packets);
+       data[ 2] = le64_to_cpu(c->tx_errors);
+       data[ 3] = le32_to_cpu(c->rx_errors);
+       data[ 4] = le16_to_cpu(c->rx_missed);
+       data[ 5] = le16_to_cpu(c->align_errors);
+       data[ 6] = le32_to_cpu(c->tx_one_collision);
+       data[ 7] = le32_to_cpu(c->tx_multi_collision);
+       data[ 8] = le64_to_cpu(c->rx_unicast);
+       data[ 9] = le64_to_cpu(c->rx_broadcast);
+       data[10] = le32_to_cpu(c->rx_multicast);
+       data[11] = le16_to_cpu(c->tx_aborted);
+       data[12] = le16_to_cpu(c->tx_underun);
 }
 
 static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 
*data)
@@ -7779,6 +7782,8 @@ static struct rtnl_link_stats64 *
 rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
+       struct rtl8169_tc_offsets *offset = &tp->tc_offset;
+       struct rtl8169_counters *counters = tp->counters;
        void __iomem *ioaddr = tp->mmio_addr;
        unsigned int start;
 
@@ -7816,12 +7821,12 @@ rtl8169_get_stats64(struct net_device *dev, struct 
rtnl_link_stats64 *stats)
         * Subtract values fetched during initalization.
         * See rtl8169_init_counter_offsets for a description why we do that.
         */
-       stats->tx_errors = le64_to_cpu(tp->counters.tx_errors) -
-               le64_to_cpu(tp->tc_offset.tx_errors);
-       stats->collisions = le32_to_cpu(tp->counters.tx_multi_collision) -
-               le32_to_cpu(tp->tc_offset.tx_multi_collision);
-       stats->tx_aborted_errors = le16_to_cpu(tp->counters.tx_aborted) -
-               le16_to_cpu(tp->tc_offset.tx_aborted);
+       stats->tx_errors = le64_to_cpu(counters->tx_errors) -
+                          le64_to_cpu(offset->tx_errors);
+       stats->collisions = le32_to_cpu(counters->tx_multi_collision) -
+                           le32_to_cpu(offset->tx_multi_collision);
+       stats->tx_aborted_errors = le16_to_cpu(counters->tx_aborted) -
+                                  le16_to_cpu(offset->tx_aborted);
 
        return stats;
 }
@@ -8022,6 +8027,8 @@ static void rtl_remove_one(struct pci_dev *pdev)
 
        unregister_netdev(dev);
 
+       kfree(tp->counters);
+
        rtl_release_firmware(tp);
 
        if (pci_dev_run_wake(pdev))
@@ -8447,9 +8454,15 @@ static int rtl_init_one(struct pci_dev *pdev, const 
struct pci_device_id *ent)
 
        tp->rtl_fw = RTL_FIRMWARE_UNKNOWN;
 
+       tp->counters = kmalloc(sizeof(*tp->counters), GFP_KERNEL);
+       if (!tp->counters) {
+               rc = -ENOMEM;
+               goto err_out_msi_4;
+       }
+
        rc = register_netdev(dev);
        if (rc < 0)
-               goto err_out_msi_4;
+               goto err_out_counters_5;
 
        pci_set_drvdata(pdev, dev);
 
@@ -8483,6 +8496,8 @@ static int rtl_init_one(struct pci_dev *pdev, const 
struct pci_device_id *ent)
 out:
        return rc;
 
+err_out_counters_5:
+       kfree(tp->counters);
 err_out_msi_4:
        netif_napi_del(&tp->napi);
        rtl_disable_msi(pdev, tp);
-- 
2.4.3

>From d7467f45553b5dca2c6ef094c49e15b2385e3659 Mon Sep 17 00:00:00 2001
Message-Id: 
<d7467f45553b5dca2c6ef094c49e15b2385e3659.1441670158.git.rom...@fr.zoreil.com>
In-Reply-To: 
<8f1b87a115f6c340558b95f6a1748ddbf866d95f.1441670158.git.rom...@fr.zoreil.com>
References: 
<8f1b87a115f6c340558b95f6a1748ddbf866d95f.1441670158.git.rom...@fr.zoreil.com>
From: Francois Romieu <rom...@fr.zoreil.com>
Date: Sat, 5 Sep 2015 13:30:41 +0200
Subject: [PATCH 2/3] r8169: use a single condition to check the completion of
 counters commands.
X-Organisation: Land of Sunshine Inc.

Signed-off-by: Francois Romieu <rom...@fr.zoreil.com>
---
 drivers/net/ethernet/realtek/r8169.c | 25 +++++++++----------------
 1 file changed, 9 insertions(+), 16 deletions(-)

diff --git a/drivers/net/ethernet/realtek/r8169.c 
b/drivers/net/ethernet/realtek/r8169.c
index ff1b834..f8a81a9 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -2190,6 +2190,13 @@ static int rtl8169_get_sset_count(struct net_device 
*dev, int sset)
        }
 }
 
+DECLARE_RTL_COND(rtl_cmd_counters_cond)
+{
+       void __iomem *ioaddr = tp->mmio_addr;
+
+       return RTL_R32(CounterAddrLow) & (CounterReset | CounterDump);
+}
+
 static struct rtl8169_counters *rtl8169_map_counters(struct net_device *dev,
                                                     dma_addr_t *paddr,
                                                     u32 counter_cmd)
@@ -2224,13 +2231,6 @@ static void rtl8169_unmap_counters (struct net_device 
*dev,
        dma_free_coherent(d, sizeof(*counters), counters, paddr);
 }
 
-DECLARE_RTL_COND(rtl_reset_counters_cond)
-{
-       void __iomem *ioaddr = tp->mmio_addr;
-
-       return RTL_R32(CounterAddrLow) & CounterReset;
-}
-
 static bool rtl8169_reset_counters(struct net_device *dev)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
@@ -2249,7 +2249,7 @@ static bool rtl8169_reset_counters(struct net_device *dev)
        if (!counters)
                return false;
 
-       if (!rtl_udelay_loop_wait_low(tp, &rtl_reset_counters_cond, 10, 1000))
+       if (!rtl_udelay_loop_wait_low(tp, &rtl_cmd_counters_cond, 10, 1000))
                ret = false;
 
        rtl8169_unmap_counters(dev, paddr, counters);
@@ -2257,13 +2257,6 @@ static bool rtl8169_reset_counters(struct net_device 
*dev)
        return ret;
 }
 
-DECLARE_RTL_COND(rtl_counters_cond)
-{
-       void __iomem *ioaddr = tp->mmio_addr;
-
-       return RTL_R32(CounterAddrLow) & CounterDump;
-}
-
 static bool rtl8169_update_counters(struct net_device *dev)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
@@ -2283,7 +2276,7 @@ static bool rtl8169_update_counters(struct net_device 
*dev)
        if (!counters)
                return false;
 
-       if (rtl_udelay_loop_wait_low(tp, &rtl_counters_cond, 10, 1000))
+       if (rtl_udelay_loop_wait_low(tp, &rtl_cmd_counters_cond, 10, 1000))
                memcpy(tp->counters, counters, sizeof(*counters));
        else
                ret = false;
-- 
2.4.3

>From 2f02fd78d644e076bc11b24e4f16c89883aa8a24 Mon Sep 17 00:00:00 2001
Message-Id: 
<2f02fd78d644e076bc11b24e4f16c89883aa8a24.1441670158.git.rom...@fr.zoreil.com>
In-Reply-To: 
<8f1b87a115f6c340558b95f6a1748ddbf866d95f.1441670158.git.rom...@fr.zoreil.com>
References: 
<8f1b87a115f6c340558b95f6a1748ddbf866d95f.1441670158.git.rom...@fr.zoreil.com>
From: Francois Romieu <rom...@fr.zoreil.com>
Date: Tue, 8 Sep 2015 00:11:58 +0200
Subject: [PATCH 3/3] r8169: increase the lifespan of the hardware counters
 dump area.
X-Organisation: Land of Sunshine Inc.

It avoids sleepable allocation when retrieving statistics as they can
happen with spinlock held (see net/core/net-sysfs.c::netstat_show).

- receive ring, transmit ring and counters dump area allocation failures
  are all considered fatal during open().
- netif_warn is now redundant with rtl_reset_counters_cond built-in
  failure message.

Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=104031
Fixes: 6e85d5ad36a2 ("r8169: Add values missing in @get_stats64 from HW 
counters")
Signed-off-by: Francois Romieu <rom...@fr.zoreil.com>
Cc: Corinna Vinschen <vinsc...@redhat.com>
---
 drivers/net/ethernet/realtek/r8169.c | 112 +++++++++++++----------------------
 1 file changed, 42 insertions(+), 70 deletions(-)

diff --git a/drivers/net/ethernet/realtek/r8169.c 
b/drivers/net/ethernet/realtek/r8169.c
index f8a81a9..afe7810 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -833,8 +833,11 @@ struct rtl8169_private {
        unsigned features;
 
        struct mii_if_info mii;
+
        struct rtl8169_counters *counters;
        struct rtl8169_tc_offsets tc_offset;
+       dma_addr_t counters_map;
+
        u32 saved_wolopts;
        u32 opts1_mask;
 
@@ -2197,104 +2200,65 @@ DECLARE_RTL_COND(rtl_cmd_counters_cond)
        return RTL_R32(CounterAddrLow) & (CounterReset | CounterDump);
 }
 
-static struct rtl8169_counters *rtl8169_map_counters(struct net_device *dev,
-                                                    dma_addr_t *paddr,
-                                                    u32 counter_cmd)
+static int rtl8169_cmd_counters(struct net_device *dev, u32 counter_cmd)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->mmio_addr;
-       struct device *d = &tp->pci_dev->dev;
-       struct rtl8169_counters *counters;
+       dma_addr_t paddr = tp->counters_map;
        u32 cmd;
+       int rc;
 
-       counters = dma_alloc_coherent(d, sizeof(*counters), paddr, GFP_KERNEL);
-       if (counters) {
-               RTL_W32(CounterAddrHigh, (u64)*paddr >> 32);
-               cmd = (u64)*paddr & DMA_BIT_MASK(32);
-               RTL_W32(CounterAddrLow, cmd);
-               RTL_W32(CounterAddrLow, cmd | counter_cmd);
-       }
-       return counters;
-}
+       RTL_W32(CounterAddrHigh, (u64)paddr >> 32);
+       cmd = (u64)paddr & DMA_BIT_MASK(32);
+       RTL_W32(CounterAddrLow, cmd);
+       RTL_W32(CounterAddrLow, cmd | counter_cmd);
 
-static void rtl8169_unmap_counters (struct net_device *dev,
-                                   dma_addr_t paddr,
-                                   struct rtl8169_counters *counters)
-{
-       struct rtl8169_private *tp = netdev_priv(dev);
-       void __iomem *ioaddr = tp->mmio_addr;
-       struct device *d = &tp->pci_dev->dev;
+       rc = rtl_udelay_loop_wait_low(tp, &rtl_cmd_counters_cond, 10, 1000);
 
        RTL_W32(CounterAddrLow, 0);
        RTL_W32(CounterAddrHigh, 0);
 
-       dma_free_coherent(d, sizeof(*counters), counters, paddr);
+       return rc;
 }
 
-static bool rtl8169_reset_counters(struct net_device *dev)
+static int rtl8169_reset_counters(struct net_device *dev)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
-       struct rtl8169_counters *counters;
-       dma_addr_t paddr;
-       bool ret = true;
 
        /*
         * Versions prior to RTL_GIGA_MAC_VER_19 don't support resetting the
         * tally counters.
         */
        if (tp->mac_version < RTL_GIGA_MAC_VER_19)
-               return true;
-
-       counters = rtl8169_map_counters(dev, &paddr, CounterReset);
-       if (!counters)
-               return false;
-
-       if (!rtl_udelay_loop_wait_low(tp, &rtl_cmd_counters_cond, 10, 1000))
-               ret = false;
-
-       rtl8169_unmap_counters(dev, paddr, counters);
+               return -EINVAL;
 
-       return ret;
+       return rtl8169_cmd_counters(dev, CounterReset);
 }
 
-static bool rtl8169_update_counters(struct net_device *dev)
+static int rtl8169_update_counters(struct net_device *dev)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->mmio_addr;
-       struct rtl8169_counters *counters;
-       dma_addr_t paddr;
-       bool ret = true;
 
        /*
         * Some chips are unable to dump tally counters when the receiver
         * is disabled.
         */
        if ((RTL_R8(ChipCmd) & CmdRxEnb) == 0)
-               return true;
-
-       counters = rtl8169_map_counters(dev, &paddr, CounterDump);
-       if (!counters)
-               return false;
-
-       if (rtl_udelay_loop_wait_low(tp, &rtl_cmd_counters_cond, 10, 1000))
-               memcpy(tp->counters, counters, sizeof(*counters));
-       else
-               ret = false;
-
-       rtl8169_unmap_counters(dev, paddr, counters);
+               return -EINVAL;
 
-       return ret;
+       return rtl8169_cmd_counters(dev, CounterDump);
 }
 
-static bool rtl8169_init_counter_offsets(struct net_device *dev)
+static int rtl_init_counter_offsets(struct net_device *dev)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
        struct rtl8169_counters *counters = tp->counters;
        struct rtl8169_tc_offsets *offset = &tp->tc_offset;
-       bool ret = false;
+       int rc;
 
        /*
-        * rtl8169_init_counter_offsets is called from rtl_open.  On chip
+        * rtl_init_counter_offsets is called from rtl_open.  On chip
         * versions prior to RTL_GIGA_MAC_VER_19 the tally counters are only
         * reset by a power cycle, while the counter values collected by the
         * driver are reset at every driver unload/load cycle.
@@ -2303,27 +2267,29 @@ static bool rtl8169_init_counter_offsets(struct 
net_device *dev)
         * values, we collect the initial values at first open(*) and use them
         * as offsets to normalize the values returned by @get_stats64.
         *
-        * (*) We can't call rtl8169_init_counter_offsets from rtl_init_one
+        * (*) We can't call rtl_init_counter_offsets from rtl_init_one
         * for the reason stated in rtl8169_update_counters; CmdRxEnb is only
         * set at open time by rtl_hw_start.
         */
 
        if (offset->inited)
-               return true;
+               return 0;
 
        /* If both, reset and update fail, propagate to caller. */
-       if (rtl8169_reset_counters(dev))
-               ret = true;
+       rc = rtl8169_reset_counters(dev);
+       if (!rc)
+               goto out;
 
-       if (rtl8169_update_counters(dev))
-               ret = true;
+       rc = rtl8169_update_counters(dev);
+       if (rc < 0)
+               goto out;
 
        offset->tx_errors = counters->tx_errors;
        offset->tx_multi_collision = counters->tx_multi_collision;
        offset->tx_aborted = counters->tx_aborted;
        offset->inited = true;
-
-       return ret;
+out:
+       return rc;
 }
 
 static void rtl8169_get_ethtool_stats(struct net_device *dev,
@@ -7741,7 +7707,8 @@ static int rtl_open(struct net_device *dev)
 
        rtl_hw_start(dev);
 
-       if (!rtl8169_init_counter_offsets(dev))
+       retval = rtl_init_counter_offsets(dev);
+       if (retval < 0)
                netif_warn(tp, hw, dev, "counter reset/update failed\n");
 
        netif_start_queue(dev);
@@ -8020,8 +7987,6 @@ static void rtl_remove_one(struct pci_dev *pdev)
 
        unregister_netdev(dev);
 
-       kfree(tp->counters);
-
        rtl_release_firmware(tp);
 
        if (pci_dev_run_wake(pdev))
@@ -8031,6 +7996,10 @@ static void rtl_remove_one(struct pci_dev *pdev)
        rtl_rar_set(tp, dev->perm_addr);
 
        rtl_disable_msi(pdev, tp);
+
+       dma_free_coherent(&pdev->dev, sizeof(*tp->counters), tp->counters,
+                         tp->counters_map);
+
        rtl8169_release_board(pdev, dev, tp->mmio_addr);
 }
 
@@ -8447,7 +8416,8 @@ static int rtl_init_one(struct pci_dev *pdev, const 
struct pci_device_id *ent)
 
        tp->rtl_fw = RTL_FIRMWARE_UNKNOWN;
 
-       tp->counters = kmalloc(sizeof(*tp->counters), GFP_KERNEL);
+       tp->counters = dma_alloc_coherent(&pdev->dev, sizeof(*tp->counters),
+                                         &tp->counters_map, GFP_KERNEL);
        if (!tp->counters) {
                rc = -ENOMEM;
                goto err_out_msi_4;
@@ -8490,7 +8460,9 @@ out:
        return rc;
 
 err_out_counters_5:
-       kfree(tp->counters);
+       dma_free_coherent(&pdev->dev, sizeof(*tp->counters), tp->counters,
+                         tp->counters_map);
+       tp->counters = NULL;
 err_out_msi_4:
        netif_napi_del(&tp->napi);
        rtl_disable_msi(pdev, tp);
-- 
2.4.3

Reply via email to