[PATCH 13/13] net: ravb: Add runtime PM support

From: Claudiu
Date: Mon Nov 20 2023 - 03:47:25 EST


From: Claudiu Beznea <claudiu.beznea.uj@xxxxxxxxxxxxxx>

RZ/G3S supports enabling/disabling clocks for its modules (including
Ethernet module). For this commit adds runtime PM support which
relies on PM domain to enable/disable Ethernet clocks.

At the end of probe ravb_pm_runtime_put() is called which will turn
off the Ethernet clocks (if no other request arrives at the driver).
After that if the interface is brought up (though ravb_open()) then
the clocks remain enabled until interface is brought down (operation
done though ravb_close()).

If any request arrives to the driver while the interface is down the
clocks are enabled to serve the request and then disabled.

Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@xxxxxxxxxxxxxx>
---
drivers/net/ethernet/renesas/ravb.h | 1 +
drivers/net/ethernet/renesas/ravb_main.c | 99 ++++++++++++++++++++++--
2 files changed, 93 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h
index c2d8d890031f..50f358472aab 100644
--- a/drivers/net/ethernet/renesas/ravb.h
+++ b/drivers/net/ethernet/renesas/ravb.h
@@ -1044,6 +1044,7 @@ struct ravb_hw_info {
unsigned magic_pkt:1; /* E-MAC supports magic packet detection */
unsigned half_duplex:1; /* E-MAC supports half duplex mode */
unsigned refclk_in_pd:1; /* Reference clock is part of a power domain. */
+ unsigned rpm:1; /* Runtime PM available. */
};

struct ravb_private {
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index f4634ac0c972..d70ed7e5f7f6 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -145,12 +145,41 @@ static void ravb_read_mac_address(struct device_node *np,
}
}

+static int ravb_pm_runtime_get(struct ravb_private *priv)
+{
+ const struct ravb_hw_info *info = priv->info;
+
+ if (!info->rpm)
+ return 0;
+
+ return pm_runtime_resume_and_get(&priv->pdev->dev);
+}
+
+static void ravb_pm_runtime_put(struct ravb_private *priv)
+{
+ const struct ravb_hw_info *info = priv->info;
+ struct device *dev = &priv->pdev->dev;
+
+ if (!info->rpm)
+ return;
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+}
+
static void ravb_mdio_ctrl(struct mdiobb_ctrl *ctrl, u32 mask, int set)
{
struct ravb_private *priv = container_of(ctrl, struct ravb_private,
mdiobb);
+ int ret;
+
+ ret = ravb_pm_runtime_get(priv);
+ if (ret < 0)
+ return;

ravb_modify(priv->ndev, PIR, mask, set ? mask : 0);
+
+ ravb_pm_runtime_put(priv);
}

/* MDC pin control */
@@ -176,8 +205,17 @@ static int ravb_get_mdio_data(struct mdiobb_ctrl *ctrl)
{
struct ravb_private *priv = container_of(ctrl, struct ravb_private,
mdiobb);
+ int ret;

- return (ravb_read(priv->ndev, PIR) & PIR_MDI) != 0;
+ ret = ravb_pm_runtime_get(priv);
+ if (ret < 0)
+ return ret;
+
+ ret = (ravb_read(priv->ndev, PIR) & PIR_MDI) != 0;
+
+ ravb_pm_runtime_put(priv);
+
+ return ret;
}

/* MDIO bus control struct */
@@ -1796,10 +1834,14 @@ static int ravb_open(struct net_device *ndev)
}
}

+ error = ravb_pm_runtime_get(priv);
+ if (error < 0)
+ return error;
+
/* Device init */
error = ravb_dmac_init(ndev);
if (error)
- goto out_free_irq_mgmta;
+ goto pm_runtime_put;
ravb_emac_init(ndev);

/* Initialise PTP Clock driver */
@@ -1820,7 +1862,8 @@ static int ravb_open(struct net_device *ndev)
if (info->gptp)
ravb_ptp_stop(ndev);
ravb_stop_dma(ndev);
-out_free_irq_mgmta:
+pm_runtime_put:
+ ravb_pm_runtime_put(priv);
if (!info->multi_irqs)
goto out_free_irq;
if (info->err_mgmt_irqs)
@@ -2064,6 +2107,11 @@ static struct net_device_stats *ravb_get_stats(struct net_device *ndev)
struct ravb_private *priv = netdev_priv(ndev);
const struct ravb_hw_info *info = priv->info;
struct net_device_stats *nstats, *stats0, *stats1;
+ int ret;
+
+ ret = ravb_pm_runtime_get(priv);
+ if (ret < 0)
+ return NULL;

nstats = &ndev->stats;
stats0 = &priv->stats[RAVB_BE];
@@ -2107,6 +2155,8 @@ static struct net_device_stats *ravb_get_stats(struct net_device *ndev)
nstats->rx_over_errors += stats1->rx_over_errors;
}

+ ravb_pm_runtime_put(priv);
+
return nstats;
}

@@ -2115,11 +2165,18 @@ static void ravb_set_rx_mode(struct net_device *ndev)
{
struct ravb_private *priv = netdev_priv(ndev);
unsigned long flags;
+ int ret;
+
+ ret = ravb_pm_runtime_get(priv);
+ if (ret < 0)
+ return;

spin_lock_irqsave(&priv->lock, flags);
ravb_modify(ndev, ECMR, ECMR_PRM,
ndev->flags & IFF_PROMISC ? ECMR_PRM : 0);
spin_unlock_irqrestore(&priv->lock, flags);
+
+ ravb_pm_runtime_put(priv);
}

/* Device close function for Ethernet AVB */
@@ -2187,6 +2244,11 @@ static int ravb_close(struct net_device *ndev)
if (info->nc_queues)
ravb_ring_free(ndev, RAVB_NC);

+ /* Note that if RPM is enabled on plaforms with ccc_gac=1 this needs to be skipped and
+ * added to suspend function after PTP is stopped.
+ */
+ ravb_pm_runtime_put(priv);
+
return 0;
}

@@ -2503,6 +2565,7 @@ static const struct ravb_hw_info gbeth_hw_info = {
.carrier_counters = 1,
.half_duplex = 1,
.refclk_in_pd = 1,
+ .rpm = 1,
};

static const struct of_device_id ravb_match_table[] = {
@@ -2636,6 +2699,12 @@ static int ravb_probe(struct platform_device *pdev)
if (error)
return error;

+ info = of_device_get_match_data(&pdev->dev);
+
+ if (info->rpm) {
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 100);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ }
pm_runtime_enable(&pdev->dev);
error = pm_runtime_resume_and_get(&pdev->dev);
if (error < 0)
@@ -2647,7 +2716,6 @@ static int ravb_probe(struct platform_device *pdev)
error = -ENOMEM;
goto pm_runtime_put;
}
- info = of_device_get_match_data(&pdev->dev);

ndev->features = info->net_features;
ndev->hw_features = info->net_hw_features;
@@ -2856,6 +2924,8 @@ static int ravb_probe(struct platform_device *pdev)

platform_set_drvdata(pdev, ndev);

+ ravb_pm_runtime_put(priv);
+
return 0;

out_napi_del:
@@ -2880,6 +2950,8 @@ static int ravb_probe(struct platform_device *pdev)
pm_runtime_put(&pdev->dev);
pm_runtime_disable:
pm_runtime_disable(&pdev->dev);
+ if (info->rpm)
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
reset_control_assert(rstc);
return error;
}
@@ -2889,6 +2961,11 @@ static void ravb_remove(struct platform_device *pdev)
struct net_device *ndev = platform_get_drvdata(pdev);
struct ravb_private *priv = netdev_priv(ndev);
const struct ravb_hw_info *info = priv->info;
+ int error;
+
+ error = ravb_pm_runtime_get(priv);
+ if (error < 0)
+ return;

/* Stop PTP Clock driver */
if (info->ccc_gac)
@@ -2908,6 +2985,8 @@ static void ravb_remove(struct platform_device *pdev)
priv->desc_bat_dma);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
+ if (info->rpm)
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
reset_control_assert(priv->rstc);
free_netdev(ndev);
platform_set_drvdata(pdev, NULL);
@@ -2989,6 +3068,10 @@ static int ravb_resume(struct device *dev)
if (ret)
return ret;

+ ret = ravb_pm_runtime_get(priv);
+ if (ret < 0)
+ return ret;
+
/* If WoL is enabled set reset mode to rearm the WoL logic */
if (priv->wol_enabled)
ravb_write(ndev, CCC_OPC_RESET, CCC);
@@ -3005,7 +3088,7 @@ static int ravb_resume(struct device *dev)
/* Set GTI value */
ret = ravb_set_gti(ndev);
if (ret)
- return ret;
+ goto pm_runtime_put;

/* Request GTI loading */
ravb_modify(ndev, GCCR, GCCR_LTI, GCCR_LTI);
@@ -3024,15 +3107,17 @@ static int ravb_resume(struct device *dev)
if (priv->wol_enabled) {
ret = ravb_wol_restore(ndev);
if (ret)
- return ret;
+ goto pm_runtime_put;
}
ret = ravb_open(ndev);
if (ret < 0)
- return ret;
+ goto pm_runtime_put;
ravb_set_rx_mode(ndev);
netif_device_attach(ndev);
}

+pm_runtime_put:
+ ravb_pm_runtime_put(priv);
return ret;
}

--
2.39.2