/* Maximum number of RXQs per port */
        unsigned int max_port_rxqs;
 
-       /* Workqueue to gather hardware statistics with its lock */
-       struct mutex gather_stats_lock;
-       struct delayed_work stats_work;
+       /* Workqueue to gather hardware statistics */
        char queue_name[30];
        struct workqueue_struct *stats_queue;
 };
        struct mvpp2_pcpu_stats __percpu *stats;
        u64 *ethtool_stats;
 
+       /* Per-port work and its lock to gather hardware statistics */
+       struct mutex gather_stats_lock;
+       struct delayed_work stats_work;
+
        phy_interface_t phy_interface;
        struct device_node *phy_node;
        struct phy *comphy;
 static void mvpp2_gather_hw_statistics(struct work_struct *work)
 {
        struct delayed_work *del_work = to_delayed_work(work);
-       struct mvpp2 *priv = container_of(del_work, struct mvpp2, stats_work);
-       struct mvpp2_port *port;
+       struct mvpp2_port *port = container_of(del_work, struct mvpp2_port,
+                                              stats_work);
        u64 *pstats;
-       int i, j;
-
-       mutex_lock(&priv->gather_stats_lock);
+       int i;
 
-       for (i = 0; i < priv->port_count; i++) {
-               if (!priv->port_list[i])
-                       continue;
+       mutex_lock(&port->gather_stats_lock);
 
-               port = priv->port_list[i];
-               pstats = port->ethtool_stats;
-               for (j = 0; j < ARRAY_SIZE(mvpp2_ethtool_regs); j++)
-                       *pstats++ += mvpp2_read_count(port,
-                                                     &mvpp2_ethtool_regs[j]);
-       }
+       pstats = port->ethtool_stats;
+       for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_regs); i++)
+               *pstats++ += mvpp2_read_count(port, &mvpp2_ethtool_regs[i]);
 
        /* No need to read again the counters right after this function if it
         * was called asynchronously by the user (ie. use of ethtool).
         */
-       cancel_delayed_work(&priv->stats_work);
-       queue_delayed_work(priv->stats_queue, &priv->stats_work,
+       cancel_delayed_work(&port->stats_work);
+       queue_delayed_work(port->priv->stats_queue, &port->stats_work,
                           MVPP2_MIB_COUNTERS_STATS_DELAY);
 
-       mutex_unlock(&priv->gather_stats_lock);
+       mutex_unlock(&port->gather_stats_lock);
 }
 
 static void mvpp2_ethtool_get_stats(struct net_device *dev,
 {
        struct mvpp2_port *port = netdev_priv(dev);
 
-       /* Update statistics for all ports, copy only those actually needed */
-       mvpp2_gather_hw_statistics(&port->priv->stats_work.work);
+       /* Update statistics for the given port, then take the lock to avoid
+        * concurrent accesses on the ethtool_stats structure during its copy.
+        */
+       mvpp2_gather_hw_statistics(&port->stats_work.work);
 
-       mutex_lock(&port->priv->gather_stats_lock);
+       mutex_lock(&port->gather_stats_lock);
        memcpy(data, port->ethtool_stats,
               sizeof(u64) * ARRAY_SIZE(mvpp2_ethtool_regs));
-       mutex_unlock(&port->priv->gather_stats_lock);
+       mutex_unlock(&port->gather_stats_lock);
 }
 
 static int mvpp2_ethtool_get_sset_count(struct net_device *dev, int sset)
                mvpp22_init_rss(port);
 
        /* Start hardware statistics gathering */
-       queue_delayed_work(priv->stats_queue, &priv->stats_work,
+       queue_delayed_work(priv->stats_queue, &port->stats_work,
                           MVPP2_MIB_COUNTERS_STATS_DELAY);
 
        return 0;
        mvpp2_cleanup_rxqs(port);
        mvpp2_cleanup_txqs(port);
 
-       cancel_delayed_work_sync(&priv->stats_work);
-       flush_workqueue(priv->stats_queue);
+       cancel_delayed_work_sync(&port->stats_work);
 
        return 0;
 }
                goto err_free_stats;
        }
 
+       mutex_init(&port->gather_stats_lock);
+       INIT_DELAYED_WORK(&port->stats_work, mvpp2_gather_hw_statistics);
+
        mvpp2_port_copy_mac_addr(dev, priv, port_node, &mac_from);
 
        port->tx_ring_size = MVPP2_MAX_TXD;
         * smallest packets (64B) will overflow a 32-bit counter in less than
         * 30 seconds. Then, use a workqueue to fill 64-bit counters.
         */
-       mutex_init(&priv->gather_stats_lock);
        snprintf(priv->queue_name, sizeof(priv->queue_name),
                 "stats-wq-%s%s", netdev_name(priv->port_list[0]->dev),
                 priv->port_count > 1 ? "+" : "");
                goto err_mg_clk;
        }
 
-       INIT_DELAYED_WORK(&priv->stats_work, mvpp2_gather_hw_statistics);
-
        platform_set_drvdata(pdev, priv);
        return 0;
 
        struct device_node *port_node;
        int i = 0;
 
+       flush_workqueue(priv->stats_queue);
        destroy_workqueue(priv->stats_queue);
-       mutex_destroy(&priv->gather_stats_lock);
 
        for_each_available_child_of_node(dn, port_node) {
-               if (priv->port_list[i])
+               if (priv->port_list[i]) {
+                       mutex_destroy(&priv->port_list[i]->gather_stats_lock);
                        mvpp2_port_remove(priv->port_list[i]);
+               }
                i++;
        }