net: stmmac: ethtool: Fixed calltrace caused by unbalanced disable_irq_wake calls
[platform/kernel/linux-starfive.git] / drivers / net / ethernet / stmicro / stmmac / stmmac_ethtool.c
index 6aa5c05..69c8c25 100644 (file)
@@ -311,8 +311,9 @@ static int stmmac_ethtool_get_link_ksettings(struct net_device *dev,
 {
        struct stmmac_priv *priv = netdev_priv(dev);
 
-       if (priv->hw->pcs & STMMAC_PCS_RGMII ||
-           priv->hw->pcs & STMMAC_PCS_SGMII) {
+       if (!(priv->plat->flags & STMMAC_FLAG_HAS_INTEGRATED_PCS) &&
+           (priv->hw->pcs & STMMAC_PCS_RGMII ||
+            priv->hw->pcs & STMMAC_PCS_SGMII)) {
                struct rgmii_adv adv;
                u32 supported, advertising, lp_advertising;
 
@@ -397,8 +398,9 @@ stmmac_ethtool_set_link_ksettings(struct net_device *dev,
 {
        struct stmmac_priv *priv = netdev_priv(dev);
 
-       if (priv->hw->pcs & STMMAC_PCS_RGMII ||
-           priv->hw->pcs & STMMAC_PCS_SGMII) {
+       if (!(priv->plat->flags & STMMAC_FLAG_HAS_INTEGRATED_PCS) &&
+           (priv->hw->pcs & STMMAC_PCS_RGMII ||
+            priv->hw->pcs & STMMAC_PCS_SGMII)) {
                /* Only support ANE */
                if (cmd->base.autoneg != AUTONEG_ENABLE)
                        return -EINVAL;
@@ -543,15 +545,12 @@ static void stmmac_get_per_qstats(struct stmmac_priv *priv, u64 *data)
        u32 rx_cnt = priv->plat->rx_queues_to_use;
        unsigned int start;
        int q, stat;
-       u64 *pos;
        char *p;
 
-       pos = data;
        for (q = 0; q < tx_cnt; q++) {
                struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[q];
                struct stmmac_txq_stats snapshot;
 
-               data = pos;
                do {
                        start = u64_stats_fetch_begin(&txq_stats->syncp);
                        snapshot = *txq_stats;
@@ -559,17 +558,15 @@ static void stmmac_get_per_qstats(struct stmmac_priv *priv, u64 *data)
 
                p = (char *)&snapshot + offsetof(struct stmmac_txq_stats, tx_pkt_n);
                for (stat = 0; stat < STMMAC_TXQ_STATS; stat++) {
-                       *data++ += (*(u64 *)p);
+                       *data++ = (*(u64 *)p);
                        p += sizeof(u64);
                }
        }
 
-       pos = data;
        for (q = 0; q < rx_cnt; q++) {
                struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[q];
                struct stmmac_rxq_stats snapshot;
 
-               data = pos;
                do {
                        start = u64_stats_fetch_begin(&rxq_stats->syncp);
                        snapshot = *rxq_stats;
@@ -577,7 +574,7 @@ static void stmmac_get_per_qstats(struct stmmac_priv *priv, u64 *data)
 
                p = (char *)&snapshot + offsetof(struct stmmac_rxq_stats, rx_pkt_n);
                for (stat = 0; stat < STMMAC_RXQ_STATS; stat++) {
-                       *data++ += (*(u64 *)p);
+                       *data++ = (*(u64 *)p);
                        p += sizeof(u64);
                }
        }
@@ -825,10 +822,16 @@ static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
        if (wol->wolopts) {
                pr_info("stmmac: wakeup enable\n");
                device_set_wakeup_enable(priv->device, 1);
-               enable_irq_wake(priv->wol_irq);
+               /* Avoid unbalanced enable_irq_wake calls */
+               if (priv->wol_irq_disabled)
+                       enable_irq_wake(priv->wol_irq);
+               priv->wol_irq_disabled = false;
        } else {
                device_set_wakeup_enable(priv->device, 0);
-               disable_irq_wake(priv->wol_irq);
+               /* Avoid unbalanced disable_irq_wake calls */
+               if (!priv->wol_irq_disabled)
+                       disable_irq_wake(priv->wol_irq);
+               priv->wol_irq_disabled = true;
        }
 
        mutex_lock(&priv->lock);