From: Claudiu Beznea <[email protected]>
Hi,
This series adds suspend to RAM and runtime PM support for Ethernet
IP available on the RZ/G3S (R9A08G045) SoC.
As there are IP versions that switch to module standby when disabling
the clocks, and because of module standby IP switches to reset and
the register content is lost, to be able to have runtime PM supported
for all IP variants, the configuration operations were moved all to
ravb_open()/ravb_close() letting the ravb_probe() and ravb_remove()
to deal with resource parsing and allocation/free.
The ethtool and IOCTL APIs that could have been run asyncronously
were adapted to return if the interface is down. As explained in
each individual commits description, this should be harmless.
Along with it, the series contains preparatory cleanups.
The series has been tested on the boards with the following device trees:
- r8a7742-iwg21d-q7.dts
- r8a774a1-hihope-rzg2m-ex.dts
- r9a07g043u11-smarc-rzg2ul.dts
- r9a07g054l2-smarc-rzv2l.dts
- r9a07g044l2-smarc-rzg2l.dts
Thank you,
Claudiu Beznea
Changes in v3:
- collected tags
- addressed review comments
- squashed patch 17/21 ("net: ravb: Keep clock request operations grouped
together") from v2 in patch 07/19 ("net: ravb: Move reference clock
enable/disable on runtime PM APIs") from v3
- check for ndev->flags & IFF_UP in patch 17/19 and 18/19 instead of
checking netif_running()
- dropped patch 19/21 ("net: ravb: Do not set promiscuous mode if the
interface is down") as the changes there are not necessary as
ndev->flags & IFF_UP is already checked at the beginning of
__dev_set_rx_mode()
- remove code from ravb_open() introduced by patch 20/21
("net: ravb: Do not apply RX CSUM settings to hardware if the interface
is down") from v2 as this is not necessary; driver already takes
care of this in ravb_emac_init_rcar()
Changes in v2:
- rework the driver (mainly, ravb_open() contains now only resource
allocation and parsing leaving the settings to ravb_open(); ravb_remove()
has been adapted accordingly) to be able to use runtime PM for all
IP variants; due to this number of patches increased
- adjust previous series to review comments
- collected tags
- populated driver's own runtime PM ops with enable/disable of reference
clock
Claudiu Beznea (19):
net: ravb: Let IP-specific receive function to interrogate descriptors
net: ravb: Rely on PM domain to enable gptp_clk
net: ravb: Make reset controller support mandatory
net: ravb: Switch to SYSTEM_SLEEP_PM_OPS()/RUNTIME_PM_OPS() and
pm_ptr()
net: ravb: Use tabs instead of spaces
net: ravb: Assert/de-assert reset on suspend/resume
net: ravb: Move reference clock enable/disable on runtime PM APIs
net: ravb: Move the IRQs get and request in the probe function
net: ravb: Split GTI computation and set operations
net: ravb: Move delay mode set in the driver's ndo_open API
net: ravb: Move DBAT configuration to the driver's ndo_open API
net: ravb: Move PTP initialization in the driver's ndo_open API for
ccc_gac platorms
net: ravb: Set config mode in ndo_open and reset mode in ndo_close
net: ravb: Simplify ravb_suspend()
net: ravb: Simplify ravb_resume()
net: ravb: Keep the reverse order of operations in ravb_close()
net: ravb: Return cached statistics if the interface is down
net: ravb: Do not apply RX CSUM settings to hardware if the interface
is down
net: ravb: Add runtime PM support
drivers/net/ethernet/renesas/ravb.h | 6 +-
drivers/net/ethernet/renesas/ravb_main.c | 760 +++++++++++------------
2 files changed, 370 insertions(+), 396 deletions(-)
--
2.39.2
From: Claudiu Beznea <[email protected]>
ravb_rzv2m_hw_info::gptp_ref_clk is enabled only for RZ/V2M. RZ/V2M
is an ARM64-based device which selects power domains by default and
CONFIG_PM. The RZ/V2M Ethernet DT node has proper power-domain binding
available in device tree from the commit that added the Ethernet node.
(4872ca1f92b0 ("arm64: dts: renesas: r9a09g011: Add ethernet nodes")).
Power domain support was available in the rzg2l-cpg.c driver when the
Ethernet DT node has been enabled in RZ/V2M device tree.
(ef3c613ccd68 ("clk: renesas: Add CPG core wrapper for RZ/G2L SoC")).
Thus, remove the explicit clock enable for gptp_clk (and treat it as the
other clocks are treated) as it is not needed and removing it doesn't
break the ABI according to the above explanations.
By removing the enable/disable operation from the driver we can add
runtime PM support (which operates on clocks) w/o the need to handle
the gptp_clk in the Ethernet driver functions like ravb_runtime_nop().
PM domain does all that is needed.
Reviewed-by: Sergey Shtylyov <[email protected]>
Signed-off-by: Claudiu Beznea <[email protected]>
---
Changes in v3:
- none
Changes in v2:
- collected tags
drivers/net/ethernet/renesas/ravb_main.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index 921f645a7218..1374dc11a7d1 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -2780,7 +2780,6 @@ static int ravb_probe(struct platform_device *pdev)
error = PTR_ERR(priv->gptp_clk);
goto out_disable_refclk;
}
- clk_prepare_enable(priv->gptp_clk);
}
ndev->max_mtu = info->rx_max_buf_size - (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN);
@@ -2806,7 +2805,7 @@ static int ravb_probe(struct platform_device *pdev)
/* Set GTI value */
error = ravb_set_gti(ndev);
if (error)
- goto out_disable_gptp_clk;
+ goto out_disable_refclk;
/* Request GTI loading */
ravb_modify(ndev, GCCR, GCCR_LTI, GCCR_LTI);
@@ -2826,7 +2825,7 @@ static int ravb_probe(struct platform_device *pdev)
"Cannot allocate desc base address table (size %d bytes)\n",
priv->desc_bat_size);
error = -ENOMEM;
- goto out_disable_gptp_clk;
+ goto out_disable_refclk;
}
for (q = RAVB_BE; q < DBAT_ENTRY_NUM; q++)
priv->desc_bat[q].die_dt = DT_EOS;
@@ -2889,8 +2888,6 @@ static int ravb_probe(struct platform_device *pdev)
/* Stop PTP Clock driver */
if (info->ccc_gac)
ravb_ptp_stop(ndev);
-out_disable_gptp_clk:
- clk_disable_unprepare(priv->gptp_clk);
out_disable_refclk:
clk_disable_unprepare(priv->refclk);
out_release:
@@ -2925,7 +2922,6 @@ static void ravb_remove(struct platform_device *pdev)
ravb_set_opmode(ndev, CCC_OPC_RESET);
- clk_disable_unprepare(priv->gptp_clk);
clk_disable_unprepare(priv->refclk);
pm_runtime_put_sync(&pdev->dev);
--
2.39.2
From: Claudiu Beznea <[email protected]>
ravb_poll() initial code used to interrogate the first descriptor of the
RX queue in case gPTP is false to determine if ravb_rx() should be called.
This is done for non-gPTP IPs. For gPTP IPs the driver PTP-specific
information was used to determine if receive function should be called. As
every IP has its own receive function that interrogates the RX descriptors
list in the same way the ravb_poll() was doing there is no need to double
check this in ravb_poll(). Removing the code from ravb_poll() leads to a
cleaner code.
Reviewed-by: Sergey Shtylyov <[email protected]>
Signed-off-by: Claudiu Beznea <[email protected]>
---
Changes in v3:
- collected Sergey's tag
Changes in v2:
- addressed review comments and keep stale code out of this patch
drivers/net/ethernet/renesas/ravb_main.c | 13 ++-----------
1 file changed, 2 insertions(+), 11 deletions(-)
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index 8649b3e90edb..921f645a7218 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -1288,25 +1288,16 @@ static int ravb_poll(struct napi_struct *napi, int budget)
struct net_device *ndev = napi->dev;
struct ravb_private *priv = netdev_priv(ndev);
const struct ravb_hw_info *info = priv->info;
- bool gptp = info->gptp || info->ccc_gac;
- struct ravb_rx_desc *desc;
unsigned long flags;
int q = napi - priv->napi;
int mask = BIT(q);
int quota = budget;
- unsigned int entry;
- if (!gptp) {
- entry = priv->cur_rx[q] % priv->num_rx_ring[q];
- desc = &priv->gbeth_rx_ring[entry];
- }
/* Processing RX Descriptor Ring */
/* Clear RX interrupt */
ravb_write(ndev, ~(mask | RIS0_RESERVED), RIS0);
- if (gptp || desc->die_dt != DT_FEMPTY) {
- if (ravb_rx(ndev, "a, q))
- goto out;
- }
+ if (ravb_rx(ndev, "a, q))
+ goto out;
/* Processing TX Descriptor Ring */
spin_lock_irqsave(&priv->lock, flags);
--
2.39.2
From: Claudiu Beznea <[email protected]>
On the RZ/G3S SoC the reset controller is mandatory for the IP to work.
The device tree binding documentation for the ravb driver specifies that
the resets are mandatory. Based on this, make the resets mandatory also in
driver for all ravb devices.
Reviewed-by: Sergey Shtylyov <[email protected]>
Reviewed-by: Geert Uytterhoeven <[email protected]>
Signed-off-by: Claudiu Beznea <[email protected]>
---
Changes in v3:
- none
Changes in v2:
- collected tags
drivers/net/ethernet/renesas/ravb_main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index 1374dc11a7d1..ce053047a9f2 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -2645,7 +2645,7 @@ static int ravb_probe(struct platform_device *pdev)
return -EINVAL;
}
- rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
+ rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
if (IS_ERR(rstc))
return dev_err_probe(&pdev->dev, PTR_ERR(rstc),
"failed to get cpg reset\n");
--
2.39.2
From: Claudiu Beznea <[email protected]>
SET_SYSTEM_SLEEP_PM_OPS() and SET_RUNTIME_PM_OPS() are deprecated now
and require __maybe_unused protection against unused function warnings.
The usage of pm_ptr() and SYSTEM_SLEEP_PM_OPS()/RUNTIME_PM_OPS() allows
the compiler to see the functions, thus suppressing the warning. Thus
drop the __maybe_unused markings.
Reviewed-by: Sergey Shtylyov <[email protected]>
Reviewed-by: Geert Uytterhoeven <[email protected]>
Signed-off-by: Claudiu Beznea <[email protected]>
---
Changes in v3:
- none
Changes in v2:
- collected tags
drivers/net/ethernet/renesas/ravb_main.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index ce053047a9f2..53ca5d984e8b 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -2971,7 +2971,7 @@ static int ravb_wol_restore(struct net_device *ndev)
return disable_irq_wake(priv->emac_irq);
}
-static int __maybe_unused ravb_suspend(struct device *dev)
+static int ravb_suspend(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct ravb_private *priv = netdev_priv(ndev);
@@ -2993,7 +2993,7 @@ static int __maybe_unused ravb_suspend(struct device *dev)
return ret;
}
-static int __maybe_unused ravb_resume(struct device *dev)
+static int ravb_resume(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct ravb_private *priv = netdev_priv(ndev);
@@ -3052,7 +3052,7 @@ static int __maybe_unused ravb_resume(struct device *dev)
return ret;
}
-static int __maybe_unused ravb_runtime_nop(struct device *dev)
+static int ravb_runtime_nop(struct device *dev)
{
/* Runtime PM callback shared between ->runtime_suspend()
* and ->runtime_resume(). Simply returns success.
@@ -3065,8 +3065,8 @@ static int __maybe_unused ravb_runtime_nop(struct device *dev)
}
static const struct dev_pm_ops ravb_dev_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(ravb_suspend, ravb_resume)
- SET_RUNTIME_PM_OPS(ravb_runtime_nop, ravb_runtime_nop, NULL)
+ SYSTEM_SLEEP_PM_OPS(ravb_suspend, ravb_resume)
+ RUNTIME_PM_OPS(ravb_runtime_nop, ravb_runtime_nop, NULL)
};
static struct platform_driver ravb_driver = {
@@ -3074,7 +3074,7 @@ static struct platform_driver ravb_driver = {
.remove_new = ravb_remove,
.driver = {
.name = "ravb",
- .pm = &ravb_dev_pm_ops,
+ .pm = pm_ptr(&ravb_dev_pm_ops),
.of_match_table = ravb_match_table,
},
};
--
2.39.2
From: Claudiu Beznea <[email protected]>
Use tabs instead of spaces in the ravb_set_rate_gbeth() function.
This aligns with the coding style requirements.
Reviewed-by: Sergey Shtylyov <[email protected]>
Signed-off-by: Claudiu Beznea <[email protected]>
---
Changes in v3:
- none
Changes in v2:
- collected tags
drivers/net/ethernet/renesas/ravb_main.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index 53ca5d984e8b..0731857c2a0c 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -96,13 +96,13 @@ static void ravb_set_rate_gbeth(struct net_device *ndev)
struct ravb_private *priv = netdev_priv(ndev);
switch (priv->speed) {
- case 10: /* 10BASE */
+ case 10: /* 10BASE */
ravb_write(ndev, GBETH_GECMR_SPEED_10, GECMR);
break;
- case 100: /* 100BASE */
+ case 100: /* 100BASE */
ravb_write(ndev, GBETH_GECMR_SPEED_100, GECMR);
break;
- case 1000: /* 1000BASE */
+ case 1000: /* 1000BASE */
ravb_write(ndev, GBETH_GECMR_SPEED_1000, GECMR);
break;
}
--
2.39.2
From: Claudiu Beznea <[email protected]>
RZ/G3S can go to deep sleep states where power to most of the SoC parts is
off. When resuming from such a state, the Ethernet controller needs to be
reinitialized. De-asserting the reset signal for it should also be done.
Thus, add reset assert/de-assert on suspend/resume functions.
On the resume function, the de-assert was not reverted in case of failures
to give the user a chance to restore the interface (e.g., bringing down/up
the interface) in case suspend/resume failed.
Reviewed-by: Sergey Shtylyov <[email protected]>
Signed-off-by: Claudiu Beznea <[email protected]>
---
Changes in v3:
- collected tags
Changes in v2:
- fixed typos in patch description and subject
- on ravb_suspend() assert the reset signal in case interface is down;
due to this the Sergey's Rb tag was left aside in this version
drivers/net/ethernet/renesas/ravb_main.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index 0731857c2a0c..844ac3306e93 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -2978,7 +2978,7 @@ static int ravb_suspend(struct device *dev)
int ret;
if (!netif_running(ndev))
- return 0;
+ goto reset_assert;
netif_device_detach(ndev);
@@ -2990,7 +2990,11 @@ static int ravb_suspend(struct device *dev)
if (priv->info->ccc_gac)
ravb_ptp_stop(ndev);
- return ret;
+ if (priv->wol_enabled)
+ return ret;
+
+reset_assert:
+ return reset_control_assert(priv->rstc);
}
static int ravb_resume(struct device *dev)
@@ -2998,7 +3002,11 @@ static int ravb_resume(struct device *dev)
struct net_device *ndev = dev_get_drvdata(dev);
struct ravb_private *priv = netdev_priv(ndev);
const struct ravb_hw_info *info = priv->info;
- int ret = 0;
+ int ret;
+
+ ret = reset_control_deassert(priv->rstc);
+ if (ret)
+ return ret;
/* If WoL is enabled set reset mode to rearm the WoL logic */
if (priv->wol_enabled) {
--
2.39.2
From: Claudiu Beznea <[email protected]>
Reference clock could be or not part of the power domain. If it is part of
the power domain, the power domain takes care of propertly setting it. In
case it is not part of the power domain and full runtime PM support is
available in driver the clock will not be propertly disabled/enabled at
runtime. For this, keep the prepare/unprepare operations in the driver's
probe()/remove() functions and move the enable/disable in runtime PM
functions.
Along with it, the other clock request operations were moved close to
reference clock request and prepare to have all the clock requests
specific code grouped together.
Reviewed-by: Sergey Shtylyov <[email protected]>
Signed-off-by: Claudiu Beznea <[email protected]>
---
Changes in v3:
- squashed with patch 17/21 ("net: ravb: Keep clock request operations grouped
together") from v2
- collected tags
Changes in v2:
- this patch is new and follows the recommendations proposed in the
discussion of patch 08/13 ("net: ravb: Rely on PM domain to enable refclk")
from v2
drivers/net/ethernet/renesas/ravb_main.c | 110 ++++++++++++-----------
1 file changed, 57 insertions(+), 53 deletions(-)
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index 844ac3306e93..4673cc2faec0 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -2664,11 +2664,6 @@ static int ravb_probe(struct platform_device *pdev)
if (error)
goto out_free_netdev;
- pm_runtime_enable(&pdev->dev);
- error = pm_runtime_resume_and_get(&pdev->dev);
- if (error < 0)
- goto out_rpm_disable;
-
if (info->multi_irqs) {
if (info->err_mgmt_irqs)
irq = platform_get_irq_byname(pdev, "dia");
@@ -2679,7 +2674,7 @@ static int ravb_probe(struct platform_device *pdev)
}
if (irq < 0) {
error = irq;
- goto out_release;
+ goto out_reset_assert;
}
ndev->irq = irq;
@@ -2697,10 +2692,37 @@ static int ravb_probe(struct platform_device *pdev)
priv->num_rx_ring[RAVB_NC] = NC_RX_RING_SIZE;
}
+ priv->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ error = PTR_ERR(priv->clk);
+ goto out_reset_assert;
+ }
+
+ if (info->gptp_ref_clk) {
+ priv->gptp_clk = devm_clk_get(&pdev->dev, "gptp");
+ if (IS_ERR(priv->gptp_clk)) {
+ error = PTR_ERR(priv->gptp_clk);
+ goto out_reset_assert;
+ }
+ }
+
+ priv->refclk = devm_clk_get_optional(&pdev->dev, "refclk");
+ if (IS_ERR(priv->refclk)) {
+ error = PTR_ERR(priv->refclk);
+ goto out_reset_assert;
+ }
+ clk_prepare(priv->refclk);
+
+ platform_set_drvdata(pdev, ndev);
+ pm_runtime_enable(&pdev->dev);
+ error = pm_runtime_resume_and_get(&pdev->dev);
+ if (error < 0)
+ goto out_rpm_disable;
+
priv->addr = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(priv->addr)) {
error = PTR_ERR(priv->addr);
- goto out_release;
+ goto out_rpm_put;
}
/* The Ether-specific entries in the device structure. */
@@ -2711,7 +2733,7 @@ static int ravb_probe(struct platform_device *pdev)
error = of_get_phy_mode(np, &priv->phy_interface);
if (error && error != -ENODEV)
- goto out_release;
+ goto out_rpm_put;
priv->no_avb_link = of_property_read_bool(np, "renesas,no-ether-link");
priv->avb_link_active_low =
@@ -2724,14 +2746,14 @@ static int ravb_probe(struct platform_device *pdev)
irq = platform_get_irq_byname(pdev, "ch24");
if (irq < 0) {
error = irq;
- goto out_release;
+ goto out_rpm_put;
}
priv->emac_irq = irq;
for (i = 0; i < NUM_RX_QUEUE; i++) {
irq = platform_get_irq_byname(pdev, ravb_rx_irqs[i]);
if (irq < 0) {
error = irq;
- goto out_release;
+ goto out_rpm_put;
}
priv->rx_irqs[i] = irq;
}
@@ -2739,7 +2761,7 @@ static int ravb_probe(struct platform_device *pdev)
irq = platform_get_irq_byname(pdev, ravb_tx_irqs[i]);
if (irq < 0) {
error = irq;
- goto out_release;
+ goto out_rpm_put;
}
priv->tx_irqs[i] = irq;
}
@@ -2748,40 +2770,19 @@ static int ravb_probe(struct platform_device *pdev)
irq = platform_get_irq_byname(pdev, "err_a");
if (irq < 0) {
error = irq;
- goto out_release;
+ goto out_rpm_put;
}
priv->erra_irq = irq;
irq = platform_get_irq_byname(pdev, "mgmt_a");
if (irq < 0) {
error = irq;
- goto out_release;
+ goto out_rpm_put;
}
priv->mgmta_irq = irq;
}
}
- priv->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(priv->clk)) {
- error = PTR_ERR(priv->clk);
- goto out_release;
- }
-
- priv->refclk = devm_clk_get_optional(&pdev->dev, "refclk");
- if (IS_ERR(priv->refclk)) {
- error = PTR_ERR(priv->refclk);
- goto out_release;
- }
- clk_prepare_enable(priv->refclk);
-
- if (info->gptp_ref_clk) {
- priv->gptp_clk = devm_clk_get(&pdev->dev, "gptp");
- if (IS_ERR(priv->gptp_clk)) {
- error = PTR_ERR(priv->gptp_clk);
- goto out_disable_refclk;
- }
- }
-
ndev->max_mtu = info->rx_max_buf_size - (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN);
ndev->min_mtu = ETH_MIN_MTU;
@@ -2799,13 +2800,13 @@ static int ravb_probe(struct platform_device *pdev)
/* Set AVB config mode */
error = ravb_set_config_mode(ndev);
if (error)
- goto out_disable_gptp_clk;
+ goto out_rpm_put;
if (info->gptp || info->ccc_gac) {
/* Set GTI value */
error = ravb_set_gti(ndev);
if (error)
- goto out_disable_refclk;
+ goto out_rpm_put;
/* Request GTI loading */
ravb_modify(ndev, GCCR, GCCR_LTI, GCCR_LTI);
@@ -2825,7 +2826,7 @@ static int ravb_probe(struct platform_device *pdev)
"Cannot allocate desc base address table (size %d bytes)\n",
priv->desc_bat_size);
error = -ENOMEM;
- goto out_disable_refclk;
+ goto out_rpm_put;
}
for (q = RAVB_BE; q < DBAT_ENTRY_NUM; q++)
priv->desc_bat[q].die_dt = DT_EOS;
@@ -2871,8 +2872,6 @@ static int ravb_probe(struct platform_device *pdev)
netdev_info(ndev, "Base address at %#x, %pM, IRQ %d.\n",
(u32)ndev->base_addr, ndev->dev_addr, ndev->irq);
- platform_set_drvdata(pdev, ndev);
-
return 0;
out_napi_del:
@@ -2888,12 +2887,12 @@ static int ravb_probe(struct platform_device *pdev)
/* Stop PTP Clock driver */
if (info->ccc_gac)
ravb_ptp_stop(ndev);
-out_disable_refclk:
- clk_disable_unprepare(priv->refclk);
-out_release:
+out_rpm_put:
pm_runtime_put(&pdev->dev);
out_rpm_disable:
pm_runtime_disable(&pdev->dev);
+ clk_unprepare(priv->refclk);
+out_reset_assert:
reset_control_assert(rstc);
out_free_netdev:
free_netdev(ndev);
@@ -2922,10 +2921,9 @@ static void ravb_remove(struct platform_device *pdev)
ravb_set_opmode(ndev, CCC_OPC_RESET);
- clk_disable_unprepare(priv->refclk);
-
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
+ clk_unprepare(priv->refclk);
reset_control_assert(priv->rstc);
free_netdev(ndev);
platform_set_drvdata(pdev, NULL);
@@ -3060,21 +3058,27 @@ static int ravb_resume(struct device *dev)
return ret;
}
-static int ravb_runtime_nop(struct device *dev)
+static int ravb_runtime_suspend(struct device *dev)
{
- /* Runtime PM callback shared between ->runtime_suspend()
- * and ->runtime_resume(). Simply returns success.
- *
- * This driver re-initializes all registers after
- * pm_runtime_get_sync() anyway so there is no need
- * to save and restore registers here.
- */
+ struct net_device *ndev = dev_get_drvdata(dev);
+ struct ravb_private *priv = netdev_priv(ndev);
+
+ clk_disable(priv->refclk);
+
return 0;
}
+static int ravb_runtime_resume(struct device *dev)
+{
+ struct net_device *ndev = dev_get_drvdata(dev);
+ struct ravb_private *priv = netdev_priv(ndev);
+
+ return clk_enable(priv->refclk);
+}
+
static const struct dev_pm_ops ravb_dev_pm_ops = {
SYSTEM_SLEEP_PM_OPS(ravb_suspend, ravb_resume)
- RUNTIME_PM_OPS(ravb_runtime_nop, ravb_runtime_nop, NULL)
+ RUNTIME_PM_OPS(ravb_runtime_suspend, ravb_runtime_resume, NULL)
};
static struct platform_driver ravb_driver = {
--
2.39.2
From: Claudiu Beznea <[email protected]>
The runtime PM implementation will disable clocks at the end of
ravb_probe(). As some IP variants switch to reset mode as a result of
setting module standby through clock disable APIs, to implement runtime PM
the resource parsing and requesting are moved in the probe function and IP
settings are moved in the open function. This is done because at the end of
the probe some IP variants will switch anyway to reset mode and the
registers content is lost. Also keeping only register specific operations
in the ravb_open()/ravb_close() functions will make them faster.
Commit moves IRQ requests to ravb_probe() to have all the IRQs ready when
the interface is open. As now IRQs gets and requests are in a single place
there is no need to keep intermediary data (like ravb_rx_irqs[] and
ravb_tx_irqs[] arrays or IRQs in struct ravb_private).
This is a preparatory change to add runtime PM support for all IP variants.
Signed-off-by: Claudiu Beznea <[email protected]>
---
Changes in v3:
- fixed typos in patch description
- detailed patch description
- reworked the code to have a single function doing IRQ get and
request
Changes in v2:
- none; this patch is new
drivers/net/ethernet/renesas/ravb.h | 4 -
drivers/net/ethernet/renesas/ravb_main.c | 258 ++++++++---------------
2 files changed, 90 insertions(+), 172 deletions(-)
diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h
index e0f8276cffed..e3506888cca6 100644
--- a/drivers/net/ethernet/renesas/ravb.h
+++ b/drivers/net/ethernet/renesas/ravb.h
@@ -1089,10 +1089,6 @@ struct ravb_private {
int msg_enable;
int speed;
int emac_irq;
- int erra_irq;
- int mgmta_irq;
- int rx_irqs[NUM_RX_QUEUE];
- int tx_irqs[NUM_TX_QUEUE];
unsigned no_avb_link:1;
unsigned avb_link_active_low:1;
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index 4673cc2faec0..ac6488ffa29a 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -38,16 +38,6 @@
NETIF_MSG_RX_ERR | \
NETIF_MSG_TX_ERR)
-static const char *ravb_rx_irqs[NUM_RX_QUEUE] = {
- "ch0", /* RAVB_BE */
- "ch1", /* RAVB_NC */
-};
-
-static const char *ravb_tx_irqs[NUM_TX_QUEUE] = {
- "ch18", /* RAVB_BE */
- "ch19", /* RAVB_NC */
-};
-
void ravb_modify(struct net_device *ndev, enum ravb_reg reg, u32 clear,
u32 set)
{
@@ -1727,85 +1717,21 @@ static const struct ethtool_ops ravb_ethtool_ops = {
.set_wol = ravb_set_wol,
};
-static inline int ravb_hook_irq(unsigned int irq, irq_handler_t handler,
- struct net_device *ndev, struct device *dev,
- const char *ch)
-{
- char *name;
- int error;
-
- name = devm_kasprintf(dev, GFP_KERNEL, "%s:%s", ndev->name, ch);
- if (!name)
- return -ENOMEM;
- error = request_irq(irq, handler, 0, name, ndev);
- if (error)
- netdev_err(ndev, "cannot request IRQ %s\n", name);
-
- return error;
-}
-
/* Network device open function for Ethernet AVB */
static int ravb_open(struct net_device *ndev)
{
struct ravb_private *priv = netdev_priv(ndev);
const struct ravb_hw_info *info = priv->info;
- struct platform_device *pdev = priv->pdev;
- struct device *dev = &pdev->dev;
int error;
napi_enable(&priv->napi[RAVB_BE]);
if (info->nc_queues)
napi_enable(&priv->napi[RAVB_NC]);
- if (!info->multi_irqs) {
- error = request_irq(ndev->irq, ravb_interrupt, IRQF_SHARED,
- ndev->name, ndev);
- if (error) {
- netdev_err(ndev, "cannot request IRQ\n");
- goto out_napi_off;
- }
- } else {
- error = ravb_hook_irq(ndev->irq, ravb_multi_interrupt, ndev,
- dev, "ch22:multi");
- if (error)
- goto out_napi_off;
- error = ravb_hook_irq(priv->emac_irq, ravb_emac_interrupt, ndev,
- dev, "ch24:emac");
- if (error)
- goto out_free_irq;
- error = ravb_hook_irq(priv->rx_irqs[RAVB_BE], ravb_be_interrupt,
- ndev, dev, "ch0:rx_be");
- if (error)
- goto out_free_irq_emac;
- error = ravb_hook_irq(priv->tx_irqs[RAVB_BE], ravb_be_interrupt,
- ndev, dev, "ch18:tx_be");
- if (error)
- goto out_free_irq_be_rx;
- error = ravb_hook_irq(priv->rx_irqs[RAVB_NC], ravb_nc_interrupt,
- ndev, dev, "ch1:rx_nc");
- if (error)
- goto out_free_irq_be_tx;
- error = ravb_hook_irq(priv->tx_irqs[RAVB_NC], ravb_nc_interrupt,
- ndev, dev, "ch19:tx_nc");
- if (error)
- goto out_free_irq_nc_rx;
-
- if (info->err_mgmt_irqs) {
- error = ravb_hook_irq(priv->erra_irq, ravb_multi_interrupt,
- ndev, dev, "err_a");
- if (error)
- goto out_free_irq_nc_tx;
- error = ravb_hook_irq(priv->mgmta_irq, ravb_multi_interrupt,
- ndev, dev, "mgmt_a");
- if (error)
- goto out_free_irq_erra;
- }
- }
-
/* Device init */
error = ravb_dmac_init(ndev);
if (error)
- goto out_free_irq_mgmta;
+ goto out_napi_off;
ravb_emac_init(ndev);
/* Initialise PTP Clock driver */
@@ -1826,26 +1752,6 @@ static int ravb_open(struct net_device *ndev)
if (info->gptp)
ravb_ptp_stop(ndev);
ravb_stop_dma(ndev);
-out_free_irq_mgmta:
- if (!info->multi_irqs)
- goto out_free_irq;
- if (info->err_mgmt_irqs)
- free_irq(priv->mgmta_irq, ndev);
-out_free_irq_erra:
- if (info->err_mgmt_irqs)
- free_irq(priv->erra_irq, ndev);
-out_free_irq_nc_tx:
- free_irq(priv->tx_irqs[RAVB_NC], ndev);
-out_free_irq_nc_rx:
- free_irq(priv->rx_irqs[RAVB_NC], ndev);
-out_free_irq_be_tx:
- free_irq(priv->tx_irqs[RAVB_BE], ndev);
-out_free_irq_be_rx:
- free_irq(priv->rx_irqs[RAVB_BE], ndev);
-out_free_irq_emac:
- free_irq(priv->emac_irq, ndev);
-out_free_irq:
- free_irq(ndev->irq, ndev);
out_napi_off:
if (info->nc_queues)
napi_disable(&priv->napi[RAVB_NC]);
@@ -2180,19 +2086,6 @@ static int ravb_close(struct net_device *ndev)
cancel_work_sync(&priv->work);
- if (info->multi_irqs) {
- free_irq(priv->tx_irqs[RAVB_NC], ndev);
- free_irq(priv->rx_irqs[RAVB_NC], ndev);
- free_irq(priv->tx_irqs[RAVB_BE], ndev);
- free_irq(priv->rx_irqs[RAVB_BE], ndev);
- free_irq(priv->emac_irq, ndev);
- if (info->err_mgmt_irqs) {
- free_irq(priv->erra_irq, ndev);
- free_irq(priv->mgmta_irq, ndev);
- }
- }
- free_irq(ndev->irq, ndev);
-
if (info->nc_queues)
napi_disable(&priv->napi[RAVB_NC]);
napi_disable(&priv->napi[RAVB_BE]);
@@ -2616,6 +2509,90 @@ static void ravb_parse_delay_mode(struct device_node *np, struct net_device *nde
}
}
+static int ravb_setup_irq(struct ravb_private *priv, const char *irq_name,
+ const char *ch, int *irq, irq_handler_t handler)
+{
+ struct platform_device *pdev = priv->pdev;
+ struct net_device *ndev = priv->ndev;
+ struct device *dev = &pdev->dev;
+ const char *dev_name;
+ unsigned long flags;
+ int error;
+
+ if (irq_name) {
+ dev_name = devm_kasprintf(dev, GFP_KERNEL, "%s:%s", ndev->name, ch);
+ if (!dev_name)
+ return -ENOMEM;
+
+ *irq = platform_get_irq_byname(pdev, irq_name);
+ flags = 0;
+ } else {
+ dev_name = ndev->name;
+ *irq = platform_get_irq(pdev, 0);
+ flags = IRQF_SHARED;
+ }
+ if (*irq < 0)
+ return *irq;
+
+ error = devm_request_irq(dev, *irq, handler, flags, dev_name, ndev);
+ if (error)
+ netdev_err(ndev, "cannot request IRQ %s\n", irq_name);
+
+ return error;
+}
+
+static int ravb_setup_irqs(struct ravb_private *priv)
+{
+ const struct ravb_hw_info *info = priv->info;
+ struct net_device *ndev = priv->ndev;
+ const char *irq_name, *emac_irq_name;
+ int error, irq;
+
+ if (!info->multi_irqs)
+ return ravb_setup_irq(priv, NULL, NULL, &ndev->irq, ravb_interrupt);
+
+ if (info->err_mgmt_irqs) {
+ irq_name = "dia";
+ emac_irq_name = "line3";
+ } else {
+ irq_name = "ch22";
+ emac_irq_name = "ch24";
+ }
+
+ error = ravb_setup_irq(priv, irq_name, "ch22:multi", &ndev->irq, ravb_multi_interrupt);
+ if (error)
+ return error;
+
+ error = ravb_setup_irq(priv, emac_irq_name, "ch24:emac", &priv->emac_irq,
+ ravb_emac_interrupt);
+ if (error)
+ return error;
+
+ if (info->err_mgmt_irqs) {
+ error = ravb_setup_irq(priv, "err_a", "err_a", &irq, ravb_multi_interrupt);
+ if (error)
+ return error;
+
+ error = ravb_setup_irq(priv, "mgmt_a", "mgmt_a", &irq, ravb_multi_interrupt);
+ if (error)
+ return error;
+ }
+
+ error = ravb_setup_irq(priv, "ch0", "ch0:rx_be", &irq, ravb_be_interrupt);
+ if (error)
+ return error;
+
+ error = ravb_setup_irq(priv, "ch1", "ch1:rx_nc", &irq, ravb_nc_interrupt);
+ if (error)
+ return error;
+
+ error = ravb_setup_irq(priv, "ch18", "ch18:tx_be", &irq, ravb_be_interrupt);
+ if (error)
+ return error;
+
+ return ravb_setup_irq(priv, "ch19", "ch19:tx_nc", &irq, ravb_nc_interrupt);
+}
+
static void ravb_set_delay_mode(struct net_device *ndev)
{
struct ravb_private *priv = netdev_priv(ndev);
@@ -2635,9 +2612,8 @@ static int ravb_probe(struct platform_device *pdev)
struct reset_control *rstc;
struct ravb_private *priv;
struct net_device *ndev;
- int error, irq, q;
struct resource *res;
- int i;
+ int error, q;
if (!np) {
dev_err(&pdev->dev,
@@ -2664,20 +2640,6 @@ static int ravb_probe(struct platform_device *pdev)
if (error)
goto out_free_netdev;
- if (info->multi_irqs) {
- if (info->err_mgmt_irqs)
- irq = platform_get_irq_byname(pdev, "dia");
- else
- irq = platform_get_irq_byname(pdev, "ch22");
- } else {
- irq = platform_get_irq(pdev, 0);
- }
- if (irq < 0) {
- error = irq;
- goto out_reset_assert;
- }
- ndev->irq = irq;
-
SET_NETDEV_DEV(ndev, &pdev->dev);
priv = netdev_priv(ndev);
@@ -2692,6 +2654,10 @@ static int ravb_probe(struct platform_device *pdev)
priv->num_rx_ring[RAVB_NC] = NC_RX_RING_SIZE;
}
+ error = ravb_setup_irqs(priv);
+ if (error)
+ goto out_reset_assert;
+
priv->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(priv->clk)) {
error = PTR_ERR(priv->clk);
@@ -2739,50 +2705,6 @@ static int ravb_probe(struct platform_device *pdev)
priv->avb_link_active_low =
of_property_read_bool(np, "renesas,ether-link-active-low");
- if (info->multi_irqs) {
- if (info->err_mgmt_irqs)
- irq = platform_get_irq_byname(pdev, "line3");
- else
- irq = platform_get_irq_byname(pdev, "ch24");
- if (irq < 0) {
- error = irq;
- goto out_rpm_put;
- }
- priv->emac_irq = irq;
- for (i = 0; i < NUM_RX_QUEUE; i++) {
- irq = platform_get_irq_byname(pdev, ravb_rx_irqs[i]);
- if (irq < 0) {
- error = irq;
- goto out_rpm_put;
- }
- priv->rx_irqs[i] = irq;
- }
- for (i = 0; i < NUM_TX_QUEUE; i++) {
- irq = platform_get_irq_byname(pdev, ravb_tx_irqs[i]);
- if (irq < 0) {
- error = irq;
- goto out_rpm_put;
- }
- priv->tx_irqs[i] = irq;
- }
-
- if (info->err_mgmt_irqs) {
- irq = platform_get_irq_byname(pdev, "err_a");
- if (irq < 0) {
- error = irq;
- goto out_rpm_put;
- }
- priv->erra_irq = irq;
-
- irq = platform_get_irq_byname(pdev, "mgmt_a");
- if (irq < 0) {
- error = irq;
- goto out_rpm_put;
- }
- priv->mgmta_irq = irq;
- }
- }
-
ndev->max_mtu = info->rx_max_buf_size - (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN);
ndev->min_mtu = ETH_MIN_MTU;
--
2.39.2
From: Claudiu Beznea <[email protected]>
ravb_set_gti() was computing the value of GTI based on the reference clock
rate and then applied it to register. This was done on the driver's probe
function. In order to implement runtime PM for all IP variants (as some IP
variants switches to reset mode (and thus the registers content is lost)
when module standby is configured through clock APIs) the GTI setup was
split in 2 parts: one computing the value of the GTI register (done in the
driver's probe function) and one applying the computed value to register
(done in the driver's ndo_open API).
Signed-off-by: Claudiu Beznea <[email protected]>
---
Changes in v3:
- fixed typos in patch description
- use u64 instead of uint64_t
- remove ravb_wait() for setting GCCR.LTI
Changes in v2:
- none; this patch is new
drivers/net/ethernet/renesas/ravb.h | 2 +
drivers/net/ethernet/renesas/ravb_main.c | 96 ++++++++++++------------
2 files changed, 52 insertions(+), 46 deletions(-)
diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h
index e3506888cca6..268ccfafe7aa 100644
--- a/drivers/net/ethernet/renesas/ravb.h
+++ b/drivers/net/ethernet/renesas/ravb.h
@@ -1102,6 +1102,8 @@ struct ravb_private {
const struct ravb_hw_info *info;
struct reset_control *rstc;
+
+ u32 gti_tiv;
};
static inline u32 ravb_read(struct net_device *ndev, enum ravb_reg reg)
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index ac6488ffa29a..f386a3b7effb 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -1717,6 +1717,50 @@ static const struct ethtool_ops ravb_ethtool_ops = {
.set_wol = ravb_set_wol,
};
+static void ravb_set_gti(struct net_device *ndev)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ const struct ravb_hw_info *info = priv->info;
+
+ if (!(info->gptp || info->ccc_gac))
+ return;
+
+ ravb_write(ndev, priv->gti_tiv, GTI);
+
+ /* Request GTI loading */
+ ravb_modify(ndev, GCCR, GCCR_LTI, GCCR_LTI);
+}
+
+static int ravb_compute_gti(struct net_device *ndev)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ const struct ravb_hw_info *info = priv->info;
+ struct device *dev = ndev->dev.parent;
+ unsigned long rate;
+ u64 inc;
+
+ if (!(info->gptp || info->ccc_gac))
+ return 0;
+
+ if (info->gptp_ref_clk)
+ rate = clk_get_rate(priv->gptp_clk);
+ else
+ rate = clk_get_rate(priv->clk);
+ if (!rate)
+ return -EINVAL;
+
+ inc = div64_ul(1000000000ULL << 20, rate);
+
+ if (inc < GTI_TIV_MIN || inc > GTI_TIV_MAX) {
+ dev_err(dev, "gti.tiv increment 0x%llx is outside the range 0x%x - 0x%x\n",
+ inc, GTI_TIV_MIN, GTI_TIV_MAX);
+ return -EINVAL;
+ }
+ priv->gti_tiv = inc;
+
+ return 0;
+}
+
/* Network device open function for Ethernet AVB */
static int ravb_open(struct net_device *ndev)
{
@@ -1734,6 +1778,8 @@ static int ravb_open(struct net_device *ndev)
goto out_napi_off;
ravb_emac_init(ndev);
+ ravb_set_gti(ndev);
+
/* Initialise PTP Clock driver */
if (info->gptp)
ravb_ptp_init(ndev, priv->pdev);
@@ -2425,34 +2471,6 @@ static const struct of_device_id ravb_match_table[] = {
};
MODULE_DEVICE_TABLE(of, ravb_match_table);
-static int ravb_set_gti(struct net_device *ndev)
-{
- struct ravb_private *priv = netdev_priv(ndev);
- const struct ravb_hw_info *info = priv->info;
- struct device *dev = ndev->dev.parent;
- unsigned long rate;
- uint64_t inc;
-
- if (info->gptp_ref_clk)
- rate = clk_get_rate(priv->gptp_clk);
- else
- rate = clk_get_rate(priv->clk);
- if (!rate)
- return -EINVAL;
-
- inc = div64_ul(1000000000ULL << 20, rate);
-
- if (inc < GTI_TIV_MIN || inc > GTI_TIV_MAX) {
- dev_err(dev, "gti.tiv increment 0x%llx is outside the range 0x%x - 0x%x\n",
- inc, GTI_TIV_MIN, GTI_TIV_MAX);
- return -EINVAL;
- }
-
- ravb_write(ndev, inc, GTI);
-
- return 0;
-}
-
static int ravb_set_config_mode(struct net_device *ndev)
{
struct ravb_private *priv = netdev_priv(ndev);
@@ -2724,15 +2742,9 @@ static int ravb_probe(struct platform_device *pdev)
if (error)
goto out_rpm_put;
- if (info->gptp || info->ccc_gac) {
- /* Set GTI value */
- error = ravb_set_gti(ndev);
- if (error)
- goto out_rpm_put;
-
- /* Request GTI loading */
- ravb_modify(ndev, GCCR, GCCR_LTI, GCCR_LTI);
- }
+ error = ravb_compute_gti(ndev);
+ if (error)
+ goto out_rpm_put;
if (info->internal_delay) {
ravb_parse_delay_mode(np, ndev);
@@ -2945,15 +2957,7 @@ static int ravb_resume(struct device *dev)
if (ret)
return ret;
- if (info->gptp || info->ccc_gac) {
- /* Set GTI value */
- ret = ravb_set_gti(ndev);
- if (ret)
- return ret;
-
- /* Request GTI loading */
- ravb_modify(ndev, GCCR, GCCR_LTI, GCCR_LTI);
- }
+ ravb_set_gti(ndev);
if (info->internal_delay)
ravb_set_delay_mode(ndev);
--
2.39.2
From: Claudiu Beznea <[email protected]>
Delay parsing and setting were done in the driver's probe API. As some IP
variants switch to reset mode (and thus registers content is lost) when
setting clocks (due to module standby functionality) to be able to
implement runtime PM keep the delay parsing in the driver's probe function
and move the delay applying function to the driver's ndo_open API.
Along with it, both delay specific functions were kept together.
Signed-off-by: Claudiu Beznea <[email protected]>
---
Changes in v3:
- fixed typos in patch description
Changes in v2:
- none; this patch is new
drivers/net/ethernet/renesas/ravb_main.c | 107 ++++++++++++-----------
1 file changed, 56 insertions(+), 51 deletions(-)
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index f386a3b7effb..946abd7606ca 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -1761,6 +1761,59 @@ static int ravb_compute_gti(struct net_device *ndev)
return 0;
}
+/* Set tx and rx clock internal delay modes */
+static void ravb_parse_delay_mode(struct device_node *np, struct net_device *ndev)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ bool explicit_delay = false;
+ u32 delay;
+
+ if (!priv->info->internal_delay)
+ return;
+
+ if (!of_property_read_u32(np, "rx-internal-delay-ps", &delay)) {
+ /* Valid values are 0 and 1800, according to DT bindings */
+ priv->rxcidm = !!delay;
+ explicit_delay = true;
+ }
+ if (!of_property_read_u32(np, "tx-internal-delay-ps", &delay)) {
+ /* Valid values are 0 and 2000, according to DT bindings */
+ priv->txcidm = !!delay;
+ explicit_delay = true;
+ }
+
+ if (explicit_delay)
+ return;
+
+ /* Fall back to legacy rgmii-*id behavior */
+ if (priv->phy_interface == PHY_INTERFACE_MODE_RGMII_ID ||
+ priv->phy_interface == PHY_INTERFACE_MODE_RGMII_RXID) {
+ priv->rxcidm = 1;
+ priv->rgmii_override = 1;
+ }
+
+ if (priv->phy_interface == PHY_INTERFACE_MODE_RGMII_ID ||
+ priv->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID) {
+ priv->txcidm = 1;
+ priv->rgmii_override = 1;
+ }
+}
+
+static void ravb_set_delay_mode(struct net_device *ndev)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ u32 set = 0;
+
+ if (!priv->info->internal_delay)
+ return;
+
+ if (priv->rxcidm)
+ set |= APSR_RDM;
+ if (priv->txcidm)
+ set |= APSR_TDM;
+ ravb_modify(ndev, APSR, APSR_RDM | APSR_TDM, set);
+}
+
/* Network device open function for Ethernet AVB */
static int ravb_open(struct net_device *ndev)
{
@@ -1772,6 +1825,8 @@ static int ravb_open(struct net_device *ndev)
if (info->nc_queues)
napi_enable(&priv->napi[RAVB_NC]);
+ ravb_set_delay_mode(ndev);
+
/* Device init */
error = ravb_dmac_init(ndev);
if (error)
@@ -2492,41 +2547,6 @@ static int ravb_set_config_mode(struct net_device *ndev)
return error;
}
-/* Set tx and rx clock internal delay modes */
-static void ravb_parse_delay_mode(struct device_node *np, struct net_device *ndev)
-{
- struct ravb_private *priv = netdev_priv(ndev);
- bool explicit_delay = false;
- u32 delay;
-
- if (!of_property_read_u32(np, "rx-internal-delay-ps", &delay)) {
- /* Valid values are 0 and 1800, according to DT bindings */
- priv->rxcidm = !!delay;
- explicit_delay = true;
- }
- if (!of_property_read_u32(np, "tx-internal-delay-ps", &delay)) {
- /* Valid values are 0 and 2000, according to DT bindings */
- priv->txcidm = !!delay;
- explicit_delay = true;
- }
-
- if (explicit_delay)
- return;
-
- /* Fall back to legacy rgmii-*id behavior */
- if (priv->phy_interface == PHY_INTERFACE_MODE_RGMII_ID ||
- priv->phy_interface == PHY_INTERFACE_MODE_RGMII_RXID) {
- priv->rxcidm = 1;
- priv->rgmii_override = 1;
- }
-
- if (priv->phy_interface == PHY_INTERFACE_MODE_RGMII_ID ||
- priv->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID) {
- priv->txcidm = 1;
- priv->rgmii_override = 1;
- }
-}
-
static int ravb_setup_irq(struct ravb_private *priv, const char *irq_name,
const char *ch, int *irq, irq_handler_t handler)
{
@@ -2611,18 +2631,6 @@ static int ravb_setup_irqs(struct ravb_private *priv)
return ravb_setup_irq(priv, "ch19", "ch19:tx_nc", &irq, ravb_nc_interrupt);
}
-static void ravb_set_delay_mode(struct net_device *ndev)
-{
- struct ravb_private *priv = netdev_priv(ndev);
- u32 set = 0;
-
- if (priv->rxcidm)
- set |= APSR_RDM;
- if (priv->txcidm)
- set |= APSR_TDM;
- ravb_modify(ndev, APSR, APSR_RDM | APSR_TDM, set);
-}
-
static int ravb_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -2746,10 +2754,7 @@ static int ravb_probe(struct platform_device *pdev)
if (error)
goto out_rpm_put;
- if (info->internal_delay) {
- ravb_parse_delay_mode(np, ndev);
- ravb_set_delay_mode(ndev);
- }
+ ravb_parse_delay_mode(np, ndev);
/* Allocate descriptor base address table */
priv->desc_bat_size = sizeof(struct ravb_desc) * DBAT_ENTRY_NUM;
--
2.39.2
From: Claudiu Beznea <[email protected]>
DBAT setup was done in the driver's probe API. As some IP variants switch
to reset mode (and thus registers content is lost) when setting clocks
(due to module standby functionality) to be able to implement runtime PM
move the DBAT configuration in the driver's ndo_open API.
This commit prepares the code for the addition of runtime PM.
Reviewed-by: Sergey Shtylyov <[email protected]>
Signed-off-by: Claudiu Beznea <[email protected]>
---
Changes in v3:
- collected tags
Changes in v2:
- none; this patch is new
drivers/net/ethernet/renesas/ravb_main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index 946abd7606ca..dbc26c3e95ec 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -1826,6 +1826,7 @@ static int ravb_open(struct net_device *ndev)
napi_enable(&priv->napi[RAVB_NC]);
ravb_set_delay_mode(ndev);
+ ravb_write(ndev, priv->desc_bat_dma, DBAT);
/* Device init */
error = ravb_dmac_init(ndev);
@@ -2769,7 +2770,6 @@ static int ravb_probe(struct platform_device *pdev)
}
for (q = RAVB_BE; q < DBAT_ENTRY_NUM; q++)
priv->desc_bat[q].die_dt = DT_EOS;
- ravb_write(ndev, priv->desc_bat_dma, DBAT);
/* Initialise HW timestamp list */
INIT_LIST_HEAD(&priv->ts_skb_list);
--
2.39.2
From: Claudiu Beznea <[email protected]>
The initialization sequence for PTP is the same for platforms with ccc_gac
and gptp (according to "Figure 50.71 Flow of gPTP Initialization (Normal,
Common to All Modes)" of the R-Car Series, 3rd generation hardware
manual and "Figure 37A.53 Flow of gPTP Initialization (Normal, Common to
All Modes)" of the RZ/G Series hardware manual).
As some IP variants switch to reset mode (and thus the registers content is
lost) when setting clocks (due to module standby functionality) to be able
to implement runtime PM, move the PTP initialization to the driver's
ndo_open API.
This commit prepares the code for the addition of runtime PM.
Reviewed-by: Sergey Shtylyov <[email protected]>
Signed-off-by: Claudiu Beznea <[email protected]>
---
Changes in v3:
- fixed typos in patch description
- collected tags
Changes in v2:
- none; this patch is new
drivers/net/ethernet/renesas/ravb_main.c | 18 +++---------------
1 file changed, 3 insertions(+), 15 deletions(-)
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index dbc26c3e95ec..1cc1ecd8d6a8 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -1837,7 +1837,7 @@ static int ravb_open(struct net_device *ndev)
ravb_set_gti(ndev);
/* Initialise PTP Clock driver */
- if (info->gptp)
+ if (info->gptp || info->ccc_gac)
ravb_ptp_init(ndev, priv->pdev);
/* PHY control start */
@@ -1851,7 +1851,7 @@ static int ravb_open(struct net_device *ndev)
out_ptp_stop:
/* Stop PTP Clock driver */
- if (info->gptp)
+ if (info->gptp || info->ccc_gac)
ravb_ptp_stop(ndev);
ravb_stop_dma(ndev);
out_napi_off:
@@ -2161,7 +2161,7 @@ static int ravb_close(struct net_device *ndev)
ravb_write(ndev, 0, TIC);
/* Stop PTP Clock driver */
- if (info->gptp)
+ if (info->gptp || info->ccc_gac)
ravb_ptp_stop(ndev);
/* Set the config mode to stop the AVB-DMAC's processes */
@@ -2774,10 +2774,6 @@ static int ravb_probe(struct platform_device *pdev)
/* Initialise HW timestamp list */
INIT_LIST_HEAD(&priv->ts_skb_list);
- /* Initialise PTP Clock driver */
- if (info->ccc_gac)
- ravb_ptp_init(ndev, pdev);
-
/* Debug message level */
priv->msg_enable = RAVB_DEF_MSG_ENABLE;
@@ -2822,10 +2818,6 @@ static int ravb_probe(struct platform_device *pdev)
out_dma_free:
dma_free_coherent(ndev->dev.parent, priv->desc_bat_size, priv->desc_bat,
priv->desc_bat_dma);
-
- /* Stop PTP Clock driver */
- if (info->ccc_gac)
- ravb_ptp_stop(ndev);
out_rpm_put:
pm_runtime_put(&pdev->dev);
out_rpm_disable:
@@ -2851,10 +2843,6 @@ static void ravb_remove(struct platform_device *pdev)
ravb_mdio_release(priv);
- /* Stop PTP Clock driver */
- if (info->ccc_gac)
- ravb_ptp_stop(ndev);
-
dma_free_coherent(ndev->dev.parent, priv->desc_bat_size, priv->desc_bat,
priv->desc_bat_dma);
--
2.39.2
From: Claudiu Beznea <[email protected]>
As some IP variants switch to reset mode (and thus registers content is
lost) when setting clocks (due to module standby functionality) to be able
to implement runtime PM and save more power, set the IP's operating mode to
reset at the end of the probe. Along with it, in the ndo_open API the IP
will be switched to configuration, then operation mode. In the ndo_close
API, the IP will be switched back to reset mode. This allows implementing
runtime PM and, along with it, save more power when the IP is not used.
Signed-off-by: Claudiu Beznea <[email protected]>
---
Changes in v3:
- fixed typos in patch description
- in ravb_probe() switch the hardware to reset mode just after phy
initialization
Changes in v2:
- none; this patch is new
drivers/net/ethernet/renesas/ravb_main.c | 78 ++++++++++++++----------
1 file changed, 46 insertions(+), 32 deletions(-)
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index 1cc1ecd8d6a8..434b4777de5e 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -1717,6 +1717,27 @@ static const struct ethtool_ops ravb_ethtool_ops = {
.set_wol = ravb_set_wol,
};
+static int ravb_set_config_mode(struct net_device *ndev)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ const struct ravb_hw_info *info = priv->info;
+ int error;
+
+ if (info->gptp) {
+ error = ravb_set_opmode(ndev, CCC_OPC_CONFIG);
+ if (error)
+ return error;
+ /* Set CSEL value */
+ ravb_modify(ndev, CCC, CCC_CSEL, CCC_CSEL_HPB);
+ } else if (info->ccc_gac) {
+ error = ravb_set_opmode(ndev, CCC_OPC_CONFIG | CCC_GAC | CCC_CSEL_HPB);
+ } else {
+ error = ravb_set_opmode(ndev, CCC_OPC_CONFIG);
+ }
+
+ return error;
+}
+
static void ravb_set_gti(struct net_device *ndev)
{
struct ravb_private *priv = netdev_priv(ndev);
@@ -1825,13 +1846,19 @@ static int ravb_open(struct net_device *ndev)
if (info->nc_queues)
napi_enable(&priv->napi[RAVB_NC]);
+ /* Set AVB config mode */
+ error = ravb_set_config_mode(ndev);
+ if (error)
+ goto out_napi_off;
+
ravb_set_delay_mode(ndev);
ravb_write(ndev, priv->desc_bat_dma, DBAT);
/* Device init */
error = ravb_dmac_init(ndev);
if (error)
- goto out_napi_off;
+ goto out_set_reset;
+
ravb_emac_init(ndev);
ravb_set_gti(ndev);
@@ -1854,6 +1881,8 @@ static int ravb_open(struct net_device *ndev)
if (info->gptp || info->ccc_gac)
ravb_ptp_stop(ndev);
ravb_stop_dma(ndev);
+out_set_reset:
+ ravb_set_opmode(ndev, CCC_OPC_RESET);
out_napi_off:
if (info->nc_queues)
napi_disable(&priv->napi[RAVB_NC]);
@@ -2197,7 +2226,8 @@ static int ravb_close(struct net_device *ndev)
if (info->nc_queues)
ravb_ring_free(ndev, RAVB_NC);
- return 0;
+ /* Set reset mode. */
+ return ravb_set_opmode(ndev, CCC_OPC_RESET);
}
static int ravb_hwtstamp_get(struct net_device *ndev, struct ifreq *req)
@@ -2527,27 +2557,6 @@ static const struct of_device_id ravb_match_table[] = {
};
MODULE_DEVICE_TABLE(of, ravb_match_table);
-static int ravb_set_config_mode(struct net_device *ndev)
-{
- struct ravb_private *priv = netdev_priv(ndev);
- const struct ravb_hw_info *info = priv->info;
- int error;
-
- if (info->gptp) {
- error = ravb_set_opmode(ndev, CCC_OPC_CONFIG);
- if (error)
- return error;
- /* Set CSEL value */
- ravb_modify(ndev, CCC, CCC_CSEL, CCC_CSEL_HPB);
- } else if (info->ccc_gac) {
- error = ravb_set_opmode(ndev, CCC_OPC_CONFIG | CCC_GAC | CCC_CSEL_HPB);
- } else {
- error = ravb_set_opmode(ndev, CCC_OPC_CONFIG);
- }
-
- return error;
-}
-
static int ravb_setup_irq(struct ravb_private *priv, const char *irq_name,
const char *ch, int *irq, irq_handler_t handler)
{
@@ -2746,11 +2755,6 @@ static int ravb_probe(struct platform_device *pdev)
ndev->netdev_ops = &ravb_netdev_ops;
ndev->ethtool_ops = &ravb_ethtool_ops;
- /* Set AVB config mode */
- error = ravb_set_config_mode(ndev);
- if (error)
- goto out_rpm_put;
-
error = ravb_compute_gti(ndev);
if (error)
goto out_rpm_put;
@@ -2785,13 +2789,23 @@ static int ravb_probe(struct platform_device *pdev)
eth_hw_addr_random(ndev);
}
+ /* Set config mode as this is needed for PHY initialization. */
+ error = ravb_set_opmode(ndev, CCC_OPC_CONFIG);
+ if (error)
+ goto out_rpm_put;
+
/* MDIO bus init */
error = ravb_mdio_init(priv);
if (error) {
dev_err(&pdev->dev, "failed to initialize MDIO\n");
- goto out_dma_free;
+ goto out_reset_mode;
}
+ /* Undo previous switch to config opmode. */
+ error = ravb_set_opmode(ndev, CCC_OPC_RESET);
+ if (error)
+ goto out_mdio_release;
+
netif_napi_add(ndev, &priv->napi[RAVB_BE], ravb_poll);
if (info->nc_queues)
netif_napi_add(ndev, &priv->napi[RAVB_NC], ravb_poll);
@@ -2814,8 +2828,10 @@ static int ravb_probe(struct platform_device *pdev)
netif_napi_del(&priv->napi[RAVB_NC]);
netif_napi_del(&priv->napi[RAVB_BE]);
+out_mdio_release:
ravb_mdio_release(priv);
-out_dma_free:
+out_reset_mode:
+ ravb_set_opmode(ndev, CCC_OPC_RESET);
dma_free_coherent(ndev->dev.parent, priv->desc_bat_size, priv->desc_bat,
priv->desc_bat_dma);
out_rpm_put:
@@ -2846,8 +2862,6 @@ static void ravb_remove(struct platform_device *pdev)
dma_free_coherent(ndev->dev.parent, priv->desc_bat_size, priv->desc_bat,
priv->desc_bat_dma);
- ravb_set_opmode(ndev, CCC_OPC_RESET);
-
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
clk_unprepare(priv->refclk);
--
2.39.2
From: Claudiu Beznea <[email protected]>
As ravb_close() contains now the call to ravb_ptp_stop() for both ccc_gac
and gPTP aware platforms, there is no need to keep the separate call in
ravb_suspend(). Instead, move it to ravb_wol_setup(). In this way the
resulting code is cleaner.
Reviewed-by: Sergey Shtylyov <[email protected]>
Signed-off-by: Claudiu Beznea <[email protected]>
---
Changes in v3:
- fixed typos in patch description
- collected tags
Changes in v2:
- none; this patch is new
drivers/net/ethernet/renesas/ravb_main.c | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index 434b4777de5e..1d228e0d875f 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -2890,6 +2890,9 @@ static int ravb_wol_setup(struct net_device *ndev)
/* Enable MagicPacket */
ravb_modify(ndev, ECMR, ECMR_MPDE, ECMR_MPDE);
+ if (priv->info->ccc_gac)
+ ravb_ptp_stop(ndev);
+
return enable_irq_wake(priv->emac_irq);
}
@@ -2922,14 +2925,10 @@ static int ravb_suspend(struct device *dev)
netif_device_detach(ndev);
if (priv->wol_enabled)
- ret = ravb_wol_setup(ndev);
- else
- ret = ravb_close(ndev);
+ return ravb_wol_setup(ndev);
- if (priv->info->ccc_gac)
- ravb_ptp_stop(ndev);
-
- if (priv->wol_enabled)
+ ret = ravb_close(ndev);
+ if (ret)
return ret;
reset_assert:
--
2.39.2
From: Claudiu Beznea <[email protected]>
Remove explicit calls to functions that are called by ravb_open(). There is
no need to have them doubled now that the ravb_open() already contains
what is needed for the interface configuration. Along with it,
configurations needed by PTP were moved to ravb_wol_restore(). With this,
code in ravb_resume() becomes simpler.
Reviewed-by: Sergey Shtylyov <[email protected]>
Signed-off-by: Claudiu Beznea <[email protected]>
---
Changes in v3:
- fixed typos in patch description
- collected tags
Changes in v2:
- none; this patch is new
drivers/net/ethernet/renesas/ravb_main.c | 58 ++++++++++--------------
1 file changed, 24 insertions(+), 34 deletions(-)
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index 1d228e0d875f..06c7ee45d567 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -2900,6 +2900,20 @@ static int ravb_wol_restore(struct net_device *ndev)
{
struct ravb_private *priv = netdev_priv(ndev);
const struct ravb_hw_info *info = priv->info;
+ int error;
+
+ /* Set reset mode to rearm the WoL logic. */
+ error = ravb_set_opmode(ndev, CCC_OPC_RESET);
+ if (error)
+ return error;
+
+ /* Set AVB config mode. */
+ error = ravb_set_config_mode(ndev);
+ if (error)
+ return error;
+
+ if (priv->info->ccc_gac)
+ ravb_ptp_init(ndev, priv->pdev);
if (info->nc_queues)
napi_enable(&priv->napi[RAVB_NC]);
@@ -2939,53 +2953,29 @@ static int ravb_resume(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct ravb_private *priv = netdev_priv(ndev);
- const struct ravb_hw_info *info = priv->info;
int ret;
ret = reset_control_deassert(priv->rstc);
if (ret)
return ret;
- /* If WoL is enabled set reset mode to rearm the WoL logic */
+ if (!netif_running(ndev))
+ return 0;
+
+ /* If WoL is enabled restore the interface. */
if (priv->wol_enabled) {
- ret = ravb_set_opmode(ndev, CCC_OPC_RESET);
+ ret = ravb_wol_restore(ndev);
if (ret)
return ret;
}
- /* All register have been reset to default values.
- * Restore all registers which where setup at probe time and
- * reopen device if it was running before system suspended.
- */
-
- /* Set AVB config mode */
- ret = ravb_set_config_mode(ndev);
- if (ret)
+ /* Reopening the interface will restore the device to the working state. */
+ ret = ravb_open(ndev);
+ if (ret < 0)
return ret;
- ravb_set_gti(ndev);
-
- if (info->internal_delay)
- ravb_set_delay_mode(ndev);
-
- /* Restore descriptor base address table */
- ravb_write(ndev, priv->desc_bat_dma, DBAT);
-
- if (priv->info->ccc_gac)
- ravb_ptp_init(ndev, priv->pdev);
-
- if (netif_running(ndev)) {
- if (priv->wol_enabled) {
- ret = ravb_wol_restore(ndev);
- if (ret)
- return ret;
- }
- ret = ravb_open(ndev);
- if (ret < 0)
- return ret;
- ravb_set_rx_mode(ndev);
- netif_device_attach(ndev);
- }
+ ravb_set_rx_mode(ndev);
+ netif_device_attach(ndev);
return ret;
}
--
2.39.2
From: Claudiu Beznea <[email protected]>
Keep the reverse order of operations in ravb_close() when compared with
ravb_open(). This is the recommended configuration sequence.
Reviewed-by: Sergey Shtylyov <[email protected]>
Signed-off-by: Claudiu Beznea <[email protected]>
---
Changes in v3:
- fixed typos in patch description
- collected tags
Changes in v2:
- none; this patch is new
drivers/net/ethernet/renesas/ravb_main.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index 06c7ee45d567..76035afd4054 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -2189,6 +2189,14 @@ static int ravb_close(struct net_device *ndev)
ravb_write(ndev, 0, RIC2);
ravb_write(ndev, 0, TIC);
+ /* PHY disconnect */
+ if (ndev->phydev) {
+ phy_stop(ndev->phydev);
+ phy_disconnect(ndev->phydev);
+ if (of_phy_is_fixed_link(np))
+ of_phy_deregister_fixed_link(np);
+ }
+
/* Stop PTP Clock driver */
if (info->gptp || info->ccc_gac)
ravb_ptp_stop(ndev);
@@ -2207,14 +2215,6 @@ static int ravb_close(struct net_device *ndev)
}
}
- /* PHY disconnect */
- if (ndev->phydev) {
- phy_stop(ndev->phydev);
- phy_disconnect(ndev->phydev);
- if (of_phy_is_fixed_link(np))
- of_phy_deregister_fixed_link(np);
- }
-
cancel_work_sync(&priv->work);
if (info->nc_queues)
--
2.39.2
From: Claudiu Beznea <[email protected]>
Return the cached statistics in case the interface is down. There should be
no drawback to this, as cached statistics are updated in ravb_close().
The commit prepares the code for the addition of runtime PM support.
Suggested-by: Sergey Shtylyov <[email protected]>
Signed-off-by: Claudiu Beznea <[email protected]>
---
Changes in v3:
- this was patch 18/21 in v2
- use ndev->flags & IFF_UP instead of netif_running checks
Changes in v2:
- none; this patch is new
drivers/net/ethernet/renesas/ravb_main.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index 76035afd4054..168b6208db37 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -2117,6 +2117,9 @@ static struct net_device_stats *ravb_get_stats(struct net_device *ndev)
const struct ravb_hw_info *info = priv->info;
struct net_device_stats *nstats, *stats0, *stats1;
+ if (!(ndev->flags & IFF_UP))
+ return &ndev->stats;
+
nstats = &ndev->stats;
stats0 = &priv->stats[RAVB_BE];
@@ -2226,6 +2229,9 @@ static int ravb_close(struct net_device *ndev)
if (info->nc_queues)
ravb_ring_free(ndev, RAVB_NC);
+ /* Update statistics. */
+ ravb_get_stats(ndev);
+
/* Set reset mode. */
return ravb_set_opmode(ndev, CCC_OPC_RESET);
}
--
2.39.2
From: Claudiu Beznea <[email protected]>
Do not apply the RX CSUM settings to hardware if the interface is down. In
case runtime PM is enabled, and while the interface is down, the IP will be
in reset mode (as for some platforms disabling the clocks will switch the
IP to reset mode, which will lead to losing registers content) and applying
settings in reset mode is not an option. Instead, cache the RX CSUM
settings and apply them in ravb_open() though ravb_emac_init().
Commit prepares for the addition of runtime PM.
Signed-off-by: Claudiu Beznea <[email protected]>
---
Changes in v3:
- this was patch 20/21 in v2
- fixed typos in patch description
- removed code from ravb_open()
- use ndev->flags & IFF_UP checks instead of netif_running()
Changes in v2:
- none; this patch is new
drivers/net/ethernet/renesas/ravb_main.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index 168b6208db37..e909960fbc30 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -2342,6 +2342,9 @@ static void ravb_set_rx_csum(struct net_device *ndev, bool enable)
struct ravb_private *priv = netdev_priv(ndev);
unsigned long flags;
+ if (!(ndev->flags & IFF_UP))
+ return;
+
spin_lock_irqsave(&priv->lock, flags);
/* Disable TX and RX */
--
2.39.2
From: Claudiu Beznea <[email protected]>
Add runtime PM support for the ravb driver. As the driver is used by
different IP variants, with different behaviors, to be able to have the
runtime PM support available for all devices, the preparatory commits
moved all the resources parsing and allocations in the driver's probe
function and kept the settings for ravb_open(). This is due to the fact
that on some IP variants-platforms tuples disabling/enabling the clocks
will switch the IP to the reset operation mode where registers' content is
lost and reconfiguration needs to be done. For this the rabv_open()
function enables the clocks, switches the IP to configuration mode, applies
all the registers settings and switches the IP to the operational mode. At
the end of ravb_open() IP is ready to send/receive data.
In ravb_close() necessary reverts are done (compared with ravb_open()), the
IP is switched to reset mode and clocks are disabled.
The ethtool APIs or IOCTLs that might execute while the interface is down
are either cached (and applied in ravb_open()) or rejected (as at that time
the IP is in reset mode). Keeping the IP in the reset mode also increases
the power saved (according to the hardware manual).
Reviewed-by: Sergey Shtylyov <[email protected]>
Signed-off-by: Claudiu Beznea <[email protected]>
---
Changes in v3:
- this was patch 21/21 in v2
- collected tags
- fixed typos in patch description
Changes in v2:
- keep RPM support for all platforms
drivers/net/ethernet/renesas/ravb_main.c | 54 ++++++++++++++++++++++--
1 file changed, 50 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index e909960fbc30..e99351fe8d7f 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -1840,16 +1840,21 @@ static int ravb_open(struct net_device *ndev)
{
struct ravb_private *priv = netdev_priv(ndev);
const struct ravb_hw_info *info = priv->info;
+ struct device *dev = &priv->pdev->dev;
int error;
napi_enable(&priv->napi[RAVB_BE]);
if (info->nc_queues)
napi_enable(&priv->napi[RAVB_NC]);
+ error = pm_runtime_resume_and_get(dev);
+ if (error < 0)
+ goto out_napi_off;
+
/* Set AVB config mode */
error = ravb_set_config_mode(ndev);
if (error)
- goto out_napi_off;
+ goto out_rpm_put;
ravb_set_delay_mode(ndev);
ravb_write(ndev, priv->desc_bat_dma, DBAT);
@@ -1883,6 +1888,9 @@ static int ravb_open(struct net_device *ndev)
ravb_stop_dma(ndev);
out_set_reset:
ravb_set_opmode(ndev, CCC_OPC_RESET);
+out_rpm_put:
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
out_napi_off:
if (info->nc_queues)
napi_disable(&priv->napi[RAVB_NC]);
@@ -2184,6 +2192,8 @@ static int ravb_close(struct net_device *ndev)
struct ravb_private *priv = netdev_priv(ndev);
const struct ravb_hw_info *info = priv->info;
struct ravb_tstamp_skb *ts_skb, *ts_skb2;
+ struct device *dev = &priv->pdev->dev;
+ int error;
netif_tx_stop_all_queues(ndev);
@@ -2233,7 +2243,14 @@ static int ravb_close(struct net_device *ndev)
ravb_get_stats(ndev);
/* Set reset mode. */
- return ravb_set_opmode(ndev, CCC_OPC_RESET);
+ error = ravb_set_opmode(ndev, CCC_OPC_RESET);
+ if (error)
+ return error;
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
+ return 0;
}
static int ravb_hwtstamp_get(struct net_device *ndev, struct ifreq *req)
@@ -2725,6 +2742,8 @@ static int ravb_probe(struct platform_device *pdev)
clk_prepare(priv->refclk);
platform_set_drvdata(pdev, ndev);
+ 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)
@@ -2830,6 +2849,9 @@ static int ravb_probe(struct platform_device *pdev)
netdev_info(ndev, "Base address at %#x, %pM, IRQ %d.\n",
(u32)ndev->base_addr, ndev->dev_addr, ndev->irq);
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_put_autosuspend(&pdev->dev);
+
return 0;
out_napi_del:
@@ -2847,6 +2869,7 @@ static int ravb_probe(struct platform_device *pdev)
pm_runtime_put(&pdev->dev);
out_rpm_disable:
pm_runtime_disable(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
clk_unprepare(priv->refclk);
out_reset_assert:
reset_control_assert(rstc);
@@ -2860,6 +2883,12 @@ 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;
+ struct device *dev = &priv->pdev->dev;
+ int error;
+
+ error = pm_runtime_resume_and_get(dev);
+ if (error < 0)
+ return;
unregister_netdev(ndev);
if (info->nc_queues)
@@ -2871,8 +2900,9 @@ static void ravb_remove(struct platform_device *pdev)
dma_free_coherent(ndev->dev.parent, priv->desc_bat_size, priv->desc_bat,
priv->desc_bat_dma);
- pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_put_sync_suspend(&pdev->dev);
pm_runtime_disable(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(dev);
clk_unprepare(priv->refclk);
reset_control_assert(priv->rstc);
free_netdev(ndev);
@@ -2954,6 +2984,10 @@ static int ravb_suspend(struct device *dev)
if (ret)
return ret;
+ ret = pm_runtime_force_suspend(&priv->pdev->dev);
+ if (ret)
+ return ret;
+
reset_assert:
return reset_control_assert(priv->rstc);
}
@@ -2976,16 +3010,28 @@ static int ravb_resume(struct device *dev)
ret = ravb_wol_restore(ndev);
if (ret)
return ret;
+ } else {
+ ret = pm_runtime_force_resume(dev);
+ if (ret)
+ return ret;
}
/* Reopening the interface will restore the device to the working state. */
ret = ravb_open(ndev);
if (ret < 0)
- return ret;
+ goto out_rpm_put;
ravb_set_rx_mode(ndev);
netif_device_attach(ndev);
+ return 0;
+
+out_rpm_put:
+ if (!priv->wol_enabled) {
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+ }
+
return ret;
}
--
2.39.2
Hi Claudiu,
On Fri, Jan 5, 2024 at 9:24 AM Claudiu <[email protected]> wrote:
> From: Claudiu Beznea <[email protected]>
>
> On the RZ/G3S SoC the reset controller is mandatory for the IP to work.
> The device tree binding documentation for the ravb driver specifies that
> the resets are mandatory. Based on this, make the resets mandatory also in
> driver for all ravb devices.
>
> Reviewed-by: Sergey Shtylyov <[email protected]>
> Reviewed-by: Geert Uytterhoeven <[email protected]>
> Signed-off-by: Claudiu Beznea <[email protected]>
> --- a/drivers/net/ethernet/renesas/ravb_main.c
> +++ b/drivers/net/ethernet/renesas/ravb_main.c
> @@ -2645,7 +2645,7 @@ static int ravb_probe(struct platform_device *pdev)
> return -EINVAL;
> }
>
> - rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
> + rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
> if (IS_ERR(rstc))
> return dev_err_probe(&pdev->dev, PTR_ERR(rstc),
> "failed to get cpg reset\n");
Upon second look, you also have to make config RAVB select
RESET_CONTROLLER.
Currently, you can build an R-Car Gen[234] kernel with RESET_CONTROLLER
disabled, causing devm_reset_control_get_exclusive() to fail
unconditionally.
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
Fri, Jan 05, 2024 at 09:23:20AM CET, [email protected] wrote:
>From: Claudiu Beznea <[email protected]>
https://www.kernel.org/doc/html/v6.6/process/maintainer-netdev.html#netdev
"don't post large series (> 15 patches), break them up"
On 1/5/24 11:23 AM, Claudiu wrote:
> From: Claudiu Beznea <[email protected]>
>
> Reference clock could be or not part of the power domain. If it is part of
> the power domain, the power domain takes care of propertly setting it. In
> case it is not part of the power domain and full runtime PM support is
> available in driver the clock will not be propertly disabled/enabled at
> runtime. For this, keep the prepare/unprepare operations in the driver's
> probe()/remove() functions and move the enable/disable in runtime PM
> functions.
>
> Along with it, the other clock request operations were moved close to
> reference clock request and prepare to have all the clock requests
> specific code grouped together.
>
> Reviewed-by: Sergey Shtylyov <[email protected]>
It's not that I reviewed the squashed version of this patch...
> Signed-off-by: Claudiu Beznea <[email protected]>
> ---
>
> Changes in v3:
> - squashed with patch 17/21 ("net: ravb: Keep clock request operations grouped
> together") from v2
> - collected tags
>
> Changes in v2:
> - this patch is new and follows the recommendations proposed in the
> discussion of patch 08/13 ("net: ravb: Rely on PM domain to enable refclk")
> from v2
>
> drivers/net/ethernet/renesas/ravb_main.c | 110 ++++++++++++-----------
> 1 file changed, 57 insertions(+), 53 deletions(-)
>
> diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
> index 844ac3306e93..4673cc2faec0 100644
> --- a/drivers/net/ethernet/renesas/ravb_main.c
> +++ b/drivers/net/ethernet/renesas/ravb_main.c
[...]
> @@ -2697,10 +2692,37 @@ static int ravb_probe(struct platform_device *pdev)
> priv->num_rx_ring[RAVB_NC] = NC_RX_RING_SIZE;
> }
>
> + priv->clk = devm_clk_get(&pdev->dev, NULL);
> + if (IS_ERR(priv->clk)) {
> + error = PTR_ERR(priv->clk);
> + goto out_reset_assert;
> + }
> +
> + if (info->gptp_ref_clk) {
> + priv->gptp_clk = devm_clk_get(&pdev->dev, "gptp");
> + if (IS_ERR(priv->gptp_clk)) {
> + error = PTR_ERR(priv->gptp_clk);
> + goto out_reset_assert;
> + }
> + }
> +
> + priv->refclk = devm_clk_get_optional(&pdev->dev, "refclk");
> + if (IS_ERR(priv->refclk)) {
> + error = PTR_ERR(priv->refclk);
> + goto out_reset_assert;
> + }
> + clk_prepare(priv->refclk);
> +
> + platform_set_drvdata(pdev, ndev);
Why exactly you had to move this line?
> + pm_runtime_enable(&pdev->dev);
> + error = pm_runtime_resume_and_get(&pdev->dev);
> + if (error < 0)
> + goto out_rpm_disable;
> +
> priv->addr = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
> if (IS_ERR(priv->addr)) {
> error = PTR_ERR(priv->addr);
> - goto out_release;
> + goto out_rpm_put;
> }
>
> /* The Ether-specific entries in the device structure. */
[...]
> @@ -2871,8 +2872,6 @@ static int ravb_probe(struct platform_device *pdev)
> netdev_info(ndev, "Base address at %#x, %pM, IRQ %d.\n",
> (u32)ndev->base_addr, ndev->dev_addr, ndev->irq);
>
> - platform_set_drvdata(pdev, ndev);
Hm, wasn't calling it here racy?
> -
> return 0;
>
> out_napi_del:
[...]
> @@ -3060,21 +3058,27 @@ static int ravb_resume(struct device *dev)
> return ret;
> }
>
> -static int ravb_runtime_nop(struct device *dev)
> +static int ravb_runtime_suspend(struct device *dev)
> {
> - /* Runtime PM callback shared between ->runtime_suspend()
> - * and ->runtime_resume(). Simply returns success.
> - *
> - * This driver re-initializes all registers after
> - * pm_runtime_get_sync() anyway so there is no need
> - * to save and restore registers here.
> - */
Perhaps even worth a separate patch to completely remove this function
which doesn't seem to make sense?
[...]
MBR, Sergey
On 1/5/24 11:23 AM, Claudiu wrote:
> From: Claudiu Beznea <[email protected]>
>
> The runtime PM implementation will disable clocks at the end of
> ravb_probe(). As some IP variants switch to reset mode as a result of
> setting module standby through clock disable APIs, to implement runtime PM
> the resource parsing and requesting are moved in the probe function and IP
> settings are moved in the open function. This is done because at the end of
> the probe some IP variants will switch anyway to reset mode and the
> registers content is lost. Also keeping only register specific operations
> in the ravb_open()/ravb_close() functions will make them faster.
>
> Commit moves IRQ requests to ravb_probe() to have all the IRQs ready when
> the interface is open. As now IRQs gets and requests are in a single place
> there is no need to keep intermediary data (like ravb_rx_irqs[] and
> ravb_tx_irqs[] arrays or IRQs in struct ravb_private).
>
> This is a preparatory change to add runtime PM support for all IP variants.
>
> Signed-off-by: Claudiu Beznea <[email protected]>
[...]
> diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h
> index e0f8276cffed..e3506888cca6 100644
> --- a/drivers/net/ethernet/renesas/ravb.h
> +++ b/drivers/net/ethernet/renesas/ravb.h
> @@ -1089,10 +1089,6 @@ struct ravb_private {
> int msg_enable;
> int speed;
> int emac_irq;
> - int erra_irq;
> - int mgmta_irq;
> - int rx_irqs[NUM_RX_QUEUE];
> - int tx_irqs[NUM_TX_QUEUE];
Good! :-)
[...]
> diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
> index 4673cc2faec0..ac6488ffa29a 100644
> --- a/drivers/net/ethernet/renesas/ravb_main.c
> +++ b/drivers/net/ethernet/renesas/ravb_main.c
[...]
> @@ -1727,85 +1717,21 @@ static const struct ethtool_ops ravb_ethtool_ops = {
> .set_wol = ravb_set_wol,
> };
>
> -static inline int ravb_hook_irq(unsigned int irq, irq_handler_t handler,
> - struct net_device *ndev, struct device *dev,
> - const char *ch)
> -{
> - char *name;
> - int error;
> -
> - name = devm_kasprintf(dev, GFP_KERNEL, "%s:%s", ndev->name, ch);
Ugh! Should've fixed this outrage... :-/
[...]
> @@ -2616,6 +2509,90 @@ static void ravb_parse_delay_mode(struct device_node *np, struct net_device *nde
> }
> }
>
> +static int ravb_setup_irq(struct ravb_private *priv, const char *irq_name,
> + const char *ch, int *irq, irq_handler_t handler)
> +{
> + struct platform_device *pdev = priv->pdev;
> + struct net_device *ndev = priv->ndev;
> + struct device *dev = &pdev->dev;
> + const char *dev_name;
> + unsigned long flags;
> + int error;
> +
> + if (irq_name) {
> + dev_name = devm_kasprintf(dev, GFP_KERNEL, "%s:%s", ndev->name, ch);
> + if (!dev_name)
> + return -ENOMEM;
> +
> + *irq = platform_get_irq_byname(pdev, irq_name);
> + flags = 0;
> + } else {
> + dev_name = ndev->name;
> + *irq = platform_get_irq(pdev, 0);
> + flags = IRQF_SHARED;
> + }
> + if (*irq < 0)
> + return *irq;
> +
> + error = devm_request_irq(dev, *irq, handler, flags, dev_name, ndev);
> + if (error)
> + netdev_err(ndev, "cannot request IRQ %s\n", irq_name);
What will be printed when irq_name is NULL? Shouldn't this be dev_name
instead?
> +
> + return error;
> +}
> +
> +static int ravb_setup_irqs(struct ravb_private *priv)
> +{
> + const struct ravb_hw_info *info = priv->info;
> + struct net_device *ndev = priv->ndev;
> + const char *irq_name, *emac_irq_name;
> + int error, irq;
> +
> + if (!info->multi_irqs)
> + return ravb_setup_irq(priv, NULL, NULL, &ndev->irq, ravb_interrupt);
> +
> + if (info->err_mgmt_irqs) {
> + irq_name = "dia";
> + emac_irq_name = "line3";
> + } else {
> + irq_name = "ch22";
> + emac_irq_name = "ch24";
> + }
> +
> + error = ravb_setup_irq(priv, irq_name, "ch22:multi", &ndev->irq, ravb_multi_interrupt);
> + if (error)
> + return error;
> +
> + error = ravb_setup_irq(priv, emac_irq_name, "ch24:emac", &priv->emac_irq,
> + ravb_emac_interrupt);
> + if (error)
> + return error;
> +
> + if (info->err_mgmt_irqs) {
> + error = ravb_setup_irq(priv, "err_a", "err_a", &irq, ravb_multi_interrupt);
Hm, why pass 2 identical names?
> + if (error)
> + return error;
> +
> + error = ravb_setup_irq(priv, "mgmt_a", "mgmt_a", &irq, ravb_multi_interrupt);
Here as well?
> + if (error)
> + return error;
> + }
> +
> + error = ravb_setup_irq(priv, "ch0", "ch0:rx_be", &irq, ravb_be_interrupt);
Hm, won't this result in "ch0:ch0:rx_be" as IRQ name?
> + if (error)
> + return error;
> +
> + error = ravb_setup_irq(priv, "ch1", "ch1:rx_nc", &irq, ravb_nc_interrupt);
Same question...
> + if (error)
> + return error;
> +
> + error = ravb_setup_irq(priv, "ch18", "ch18:tx_be", &irq, ravb_be_interrupt);
And here as well...
> + if (error)
> + return error;
> +
> + return ravb_setup_irq(priv, "ch19", "ch19:tx_nc", &irq, ravb_nc_interrupt);
Here too...
[...]
MBR, Sergey
On 1/5/24 11:23 AM, Claudiu wrote:
> From: Claudiu Beznea <[email protected]>
>
> ravb_set_gti() was computing the value of GTI based on the reference clock
> rate and then applied it to register. This was done on the driver's probe
> function. In order to implement runtime PM for all IP variants (as some IP
> variants switches to reset mode (and thus the registers content is lost)
> when module standby is configured through clock APIs) the GTI setup was
> split in 2 parts: one computing the value of the GTI register (done in the
> driver's probe function) and one applying the computed value to register
> (done in the driver's ndo_open API).
>
> Signed-off-by: Claudiu Beznea <[email protected]>
Reviewed-by: Sergey Shtylyov <[email protected]>
> ---
>
> Changes in v3:
> - fixed typos in patch description
> - use u64 instead of uint64_t
Well, u64 in one place, u32 in another...
> - remove ravb_wait() for setting GCCR.LTI
[...]
MBR, Sergey
On 1/5/24 11:23 AM, Claudiu wrote:
> From: Claudiu Beznea <[email protected]>
>
> Delay parsing and setting were done in the driver's probe API. As some IP
> variants switch to reset mode (and thus registers content is lost) when
> setting clocks (due to module standby functionality) to be able to
> implement runtime PM keep the delay parsing in the driver's probe function
> and move the delay applying function to the driver's ndo_open API.
>
> Along with it, both delay specific functions were kept together.
>
> Signed-off-by: Claudiu Beznea <[email protected]>
Reviewed-by: Sergey Shtylyov <[email protected]>
[...]
> diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
> index f386a3b7effb..946abd7606ca 100644
> --- a/drivers/net/ethernet/renesas/ravb_main.c
> +++ b/drivers/net/ethernet/renesas/ravb_main.c
[...]
> @@ -1772,6 +1825,8 @@ static int ravb_open(struct net_device *ndev)
> if (info->nc_queues)
> napi_enable(&priv->napi[RAVB_NC]);
>
> + ravb_set_delay_mode(ndev);
> +
Please consider moving to either ravb_dmac_init() or ravb_emac_init(),
at least in the future...
> /* Device init */
> error = ravb_dmac_init(ndev);
> if (error)
[...]
MBR, Sergey
On 1/5/24 11:23 AM, Claudiu wrote:
> From: Claudiu Beznea <[email protected]>
>
> DBAT setup was done in the driver's probe API. As some IP variants switch
> to reset mode (and thus registers content is lost) when setting clocks
> (due to module standby functionality) to be able to implement runtime PM
> move the DBAT configuration in the driver's ndo_open API.
>
> This commit prepares the code for the addition of runtime PM.
>
> Reviewed-by: Sergey Shtylyov <[email protected]>
> Signed-off-by: Claudiu Beznea <[email protected]>
[...]
> diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
> index 946abd7606ca..dbc26c3e95ec 100644
> --- a/drivers/net/ethernet/renesas/ravb_main.c
> +++ b/drivers/net/ethernet/renesas/ravb_main.c
> @@ -1826,6 +1826,7 @@ static int ravb_open(struct net_device *ndev)
> napi_enable(&priv->napi[RAVB_NC]);
>
> ravb_set_delay_mode(ndev);
> + ravb_write(ndev, priv->desc_bat_dma, DBAT);
Please do consider moving this to ravb_dmac_init(), at least in
the future...
>
> /* Device init */
> error = ravb_dmac_init(ndev);
MBR, Sergey
On 1/5/24 11:23 AM, Claudiu wrote:
> From: Claudiu Beznea <[email protected]>
>
> The runtime PM implementation will disable clocks at the end of
> ravb_probe(). As some IP variants switch to reset mode as a result of
> setting module standby through clock disable APIs, to implement runtime PM
> the resource parsing and requesting are moved in the probe function and IP
> settings are moved in the open function. This is done because at the end of
> the probe some IP variants will switch anyway to reset mode and the
> registers content is lost. Also keeping only register specific operations
> in the ravb_open()/ravb_close() functions will make them faster.
>
> Commit moves IRQ requests to ravb_probe() to have all the IRQs ready when
> the interface is open. As now IRQs gets and requests are in a single place
> there is no need to keep intermediary data (like ravb_rx_irqs[] and
> ravb_tx_irqs[] arrays or IRQs in struct ravb_private).
There's one thing that you probably didn't take into account: after
you call request_irq(), you should be able to handle your IRQ as it's
automatically unmasked, unless you pass IRQF_NO_AUTOEN to request_irq().
Your device may be held i reset or even powered off but if you pass IRQF_SHARED to request_irq() (you do in a single IRQ config), you must
be prepared to get your device's registers read (in order to ascertain
whether it's your IRQ or not). And you can't even pass IRQF_NO_AUTOEN
along with IRQF_SHARED, according to my reading of the IRQ code...
> This is a preparatory change to add runtime PM support for all IP variants.
I don't readily see why this is necessary for the full-fledged RPM
support...
> Signed-off-by: Claudiu Beznea <[email protected]>
Unfortunately, I have to NAK this patch, at least in its current
form...
[...]
MBR, Sergey
Hi, Geert,
On 05.01.2024 11:38, Geert Uytterhoeven wrote:
> Hi Claudiu,
>
> On Fri, Jan 5, 2024 at 9:24 AM Claudiu <[email protected]> wrote:
>> From: Claudiu Beznea <[email protected]>
>>
>> On the RZ/G3S SoC the reset controller is mandatory for the IP to work.
>> The device tree binding documentation for the ravb driver specifies that
>> the resets are mandatory. Based on this, make the resets mandatory also in
>> driver for all ravb devices.
>>
>> Reviewed-by: Sergey Shtylyov <[email protected]>
>> Reviewed-by: Geert Uytterhoeven <[email protected]>
>> Signed-off-by: Claudiu Beznea <[email protected]>
>
>> --- a/drivers/net/ethernet/renesas/ravb_main.c
>> +++ b/drivers/net/ethernet/renesas/ravb_main.c
>> @@ -2645,7 +2645,7 @@ static int ravb_probe(struct platform_device *pdev)
>> return -EINVAL;
>> }
>>
>> - rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
>> + rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
>> if (IS_ERR(rstc))
>> return dev_err_probe(&pdev->dev, PTR_ERR(rstc),
>> "failed to get cpg reset\n");
>
> Upon second look, you also have to make config RAVB select
> RESET_CONTROLLER.
> Currently, you can build an R-Car Gen[234] kernel with RESET_CONTROLLER
> disabled, causing devm_reset_control_get_exclusive() to fail
> unconditionally.
ok, I'll update it. Thanks!
>
> Gr{oetje,eeting}s,
>
> Geert
>
On 05.01.2024 21:52, Sergey Shtylyov wrote:
> On 1/5/24 11:23 AM, Claudiu wrote:
>
>> From: Claudiu Beznea <[email protected]>
>>
>> Reference clock could be or not part of the power domain. If it is part of
>> the power domain, the power domain takes care of propertly setting it. In
>> case it is not part of the power domain and full runtime PM support is
>> available in driver the clock will not be propertly disabled/enabled at
>> runtime. For this, keep the prepare/unprepare operations in the driver's
>> probe()/remove() functions and move the enable/disable in runtime PM
>> functions.
>>
>> Along with it, the other clock request operations were moved close to
>> reference clock request and prepare to have all the clock requests
>> specific code grouped together.
>>
>> Reviewed-by: Sergey Shtylyov <[email protected]>
>
> It's not that I reviewed the squashed version of this patch...
I had a Rb on "net: ravb: Move reference clock enable/disable on runtime PM
APIs" from v2 and an OK from you (no other comments) to do the squash on
"net: ravb: Keep clock request operations grouped together" from v2 thus I
consider keeping Rb is OK.
>
>> Signed-off-by: Claudiu Beznea <[email protected]>
>> ---
>>
>> Changes in v3:
>> - squashed with patch 17/21 ("net: ravb: Keep clock request operations grouped
>> together") from v2
>> - collected tags
>>
>> Changes in v2:
>> - this patch is new and follows the recommendations proposed in the
>> discussion of patch 08/13 ("net: ravb: Rely on PM domain to enable refclk")
>> from v2
>>
>> drivers/net/ethernet/renesas/ravb_main.c | 110 ++++++++++++-----------
>> 1 file changed, 57 insertions(+), 53 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
>> index 844ac3306e93..4673cc2faec0 100644
>> --- a/drivers/net/ethernet/renesas/ravb_main.c
>> +++ b/drivers/net/ethernet/renesas/ravb_main.c
> [...]
>> @@ -2697,10 +2692,37 @@ static int ravb_probe(struct platform_device *pdev)
>> priv->num_rx_ring[RAVB_NC] = NC_RX_RING_SIZE;
>> }
>>
>> + priv->clk = devm_clk_get(&pdev->dev, NULL);
>> + if (IS_ERR(priv->clk)) {
>> + error = PTR_ERR(priv->clk);
>> + goto out_reset_assert;
>> + }
>> +
>> + if (info->gptp_ref_clk) {
>> + priv->gptp_clk = devm_clk_get(&pdev->dev, "gptp");
>> + if (IS_ERR(priv->gptp_clk)) {
>> + error = PTR_ERR(priv->gptp_clk);
>> + goto out_reset_assert;
>> + }
>> + }
>> +
>> + priv->refclk = devm_clk_get_optional(&pdev->dev, "refclk");
>> + if (IS_ERR(priv->refclk)) {
>> + error = PTR_ERR(priv->refclk);
>> + goto out_reset_assert;
>> + }
>> + clk_prepare(priv->refclk);
>> +
>> + platform_set_drvdata(pdev, ndev);
>
> Why exactly you had to move this line?
Calling pm_runtime_resume_and_get() above will implicitly call the
ravb_runtime_resume() which calls dev_get_drvdata() to get proper data for
refclk.
>
>> + pm_runtime_enable(&pdev->dev);
>> + error = pm_runtime_resume_and_get(&pdev->dev);
>> + if (error < 0)
>> + goto out_rpm_disable;
>> +
>> priv->addr = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
>> if (IS_ERR(priv->addr)) {
>> error = PTR_ERR(priv->addr);
>> - goto out_release;
>> + goto out_rpm_put;
>> }
>>
>> /* The Ether-specific entries in the device structure. */
> [...]
>> @@ -2871,8 +2872,6 @@ static int ravb_probe(struct platform_device *pdev)
>> netdev_info(ndev, "Base address at %#x, %pM, IRQ %d.\n",
>> (u32)ndev->base_addr, ndev->dev_addr, ndev->irq);
>>
>> - platform_set_drvdata(pdev, ndev);
>
> Hm, wasn't calling it here racy?
Haven't noticed that. Racing with who? AFAICT the only functions that uses
this are remove, suspend, resume specific ones.
>
>> -
>> return 0;
>>
>> out_napi_del:
> [...]
>> @@ -3060,21 +3058,27 @@ static int ravb_resume(struct device *dev)
>> return ret;
>> }
>>
>> -static int ravb_runtime_nop(struct device *dev)
>> +static int ravb_runtime_suspend(struct device *dev)
>> {
>> - /* Runtime PM callback shared between ->runtime_suspend()
>> - * and ->runtime_resume(). Simply returns success.
>> - *
>> - * This driver re-initializes all registers after
>> - * pm_runtime_get_sync() anyway so there is no need
>> - * to save and restore registers here.
>> - */
>
> Perhaps even worth a separate patch to completely remove this function
> which doesn't seem to make sense?
Why? With that the refclk will not be properly enabled/disabled when it
will not be part of the power domain. Take
https://elixir.bootlin.com/linux/v6.7/source/arch/arm64/boot/dts/renesas/beacon-renesom-som.dtsi#L57
as an example. Here refclk is from an external source (not part of power
domain).
Thank you,
Claudiu Beznea
>
> [...]
>
> MBR, Sergey
On 05.01.2024 22:57, Sergey Shtylyov wrote:
> On 1/5/24 11:23 AM, Claudiu wrote:
>
>> From: Claudiu Beznea <[email protected]>
>>
>> The runtime PM implementation will disable clocks at the end of
>> ravb_probe(). As some IP variants switch to reset mode as a result of
>> setting module standby through clock disable APIs, to implement runtime PM
>> the resource parsing and requesting are moved in the probe function and IP
>> settings are moved in the open function. This is done because at the end of
>> the probe some IP variants will switch anyway to reset mode and the
>> registers content is lost. Also keeping only register specific operations
>> in the ravb_open()/ravb_close() functions will make them faster.
>>
>> Commit moves IRQ requests to ravb_probe() to have all the IRQs ready when
>> the interface is open. As now IRQs gets and requests are in a single place
>> there is no need to keep intermediary data (like ravb_rx_irqs[] and
>> ravb_tx_irqs[] arrays or IRQs in struct ravb_private).
>>
>> This is a preparatory change to add runtime PM support for all IP variants.
>>
>> Signed-off-by: Claudiu Beznea <[email protected]>
> [...]
>> diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h
>> index e0f8276cffed..e3506888cca6 100644
>> --- a/drivers/net/ethernet/renesas/ravb.h
>> +++ b/drivers/net/ethernet/renesas/ravb.h
>> @@ -1089,10 +1089,6 @@ struct ravb_private {
>> int msg_enable;
>> int speed;
>> int emac_irq;
>> - int erra_irq;
>> - int mgmta_irq;
>> - int rx_irqs[NUM_RX_QUEUE];
>> - int tx_irqs[NUM_TX_QUEUE];
>
> Good! :-)
>
> [...]
>> diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
>> index 4673cc2faec0..ac6488ffa29a 100644
>> --- a/drivers/net/ethernet/renesas/ravb_main.c
>> +++ b/drivers/net/ethernet/renesas/ravb_main.c
> [...]
>> @@ -1727,85 +1717,21 @@ static const struct ethtool_ops ravb_ethtool_ops = {
>> .set_wol = ravb_set_wol,
>> };
>>
>> -static inline int ravb_hook_irq(unsigned int irq, irq_handler_t handler,
>> - struct net_device *ndev, struct device *dev,
>> - const char *ch)
>> -{
>> - char *name;
>> - int error;
>> -
>> - name = devm_kasprintf(dev, GFP_KERNEL, "%s:%s", ndev->name, ch);
>
> Ugh! Should've fixed this outrage... :-/
>
> [...]
>> @@ -2616,6 +2509,90 @@ static void ravb_parse_delay_mode(struct device_node *np, struct net_device *nde
>> }
>> }
>>
>> +static int ravb_setup_irq(struct ravb_private *priv, const char *irq_name,
>> + const char *ch, int *irq, irq_handler_t handler)
>> +{
>> + struct platform_device *pdev = priv->pdev;
>> + struct net_device *ndev = priv->ndev;
>> + struct device *dev = &pdev->dev;
>> + const char *dev_name;
>> + unsigned long flags;
>> + int error;
>> +
>> + if (irq_name) {
>> + dev_name = devm_kasprintf(dev, GFP_KERNEL, "%s:%s", ndev->name, ch);
>> + if (!dev_name)
>> + return -ENOMEM;
>> +
>> + *irq = platform_get_irq_byname(pdev, irq_name);
>> + flags = 0;
>> + } else {
>> + dev_name = ndev->name;
>> + *irq = platform_get_irq(pdev, 0);
>> + flags = IRQF_SHARED;
>> + }
>> + if (*irq < 0)
>> + return *irq;
>> +
>> + error = devm_request_irq(dev, *irq, handler, flags, dev_name, ndev);
>> + if (error)
>> + netdev_err(ndev, "cannot request IRQ %s\n", irq_name);
>
> What will be printed when irq_name is NULL? Shouldn't this be dev_name
> instead?
Indeed, should have been dev_name.
Maybe better would be to have irq_name and IRQ0 instead as the users of
this don't request IRQ from buf (where buf is sprintf(buf, "%s:%s",
ndev->name, ch)) but they request irq_name or IRQ0.
>
>> +
>> + return error;
>> +}
>> +
>> +static int ravb_setup_irqs(struct ravb_private *priv)
>> +{
>> + const struct ravb_hw_info *info = priv->info;
>> + struct net_device *ndev = priv->ndev;
>> + const char *irq_name, *emac_irq_name;
>> + int error, irq;
>> +
>> + if (!info->multi_irqs)
>> + return ravb_setup_irq(priv, NULL, NULL, &ndev->irq, ravb_interrupt);
>> +
>> + if (info->err_mgmt_irqs) {
>> + irq_name = "dia";
>> + emac_irq_name = "line3";
>> + } else {
>> + irq_name = "ch22";
>> + emac_irq_name = "ch24";
>> + }
>> +
>> + error = ravb_setup_irq(priv, irq_name, "ch22:multi", &ndev->irq, ravb_multi_interrupt);
>> + if (error)
>> + return error;
>> +
>> + error = ravb_setup_irq(priv, emac_irq_name, "ch24:emac", &priv->emac_irq,
>> + ravb_emac_interrupt);
>> + if (error)
>> + return error;
>> +
>> + if (info->err_mgmt_irqs) {
>> + error = ravb_setup_irq(priv, "err_a", "err_a", &irq, ravb_multi_interrupt);
>
> Hm, why pass 2 identical names?
1st name is what is used by platform_get_irq_by_name(), 2nd name is used to
fill the name of the IRQ after it has been requested. Perviously the same
naming schema was used.
>
>> + if (error)
>> + return error;
>> +
>> + error = ravb_setup_irq(priv, "mgmt_a", "mgmt_a", &irq, ravb_multi_interrupt);
>
> Here as well?
>
>> + if (error)
>> + return error;
>> + }
>> +
>> + error = ravb_setup_irq(priv, "ch0", "ch0:rx_be", &irq, ravb_be_interrupt);
>
> Hm, won't this result in "ch0:ch0:rx_be" as IRQ name?
No, first "ch0" is to call:
platform_get_irq_byname(pdev, "ch0");
"ch0:rx_be" is passed to
devm_kasprintf(..., "%s:%s", ndev->name, "ch0:rx_be");
and fill the name of IRQ after devm_request_irq(). Previously it was the same.
>
>> + if (error)
>> + return error;
>> +
>> + error = ravb_setup_irq(priv, "ch1", "ch1:rx_nc", &irq, ravb_nc_interrupt);
>
> Same question...
>
>> + if (error)
>> + return error;
>> +
>> + error = ravb_setup_irq(priv, "ch18", "ch18:tx_be", &irq, ravb_be_interrupt);
>
> And here as well...
>
>> + if (error)
>> + return error;
>> +
>> + return ravb_setup_irq(priv, "ch19", "ch19:tx_nc", &irq, ravb_nc_interrupt);
>
> Here too...
>
> [...]
>
> MBR, Sergey
On 07.01.2024 20:24, Sergey Shtylyov wrote:
> On 1/5/24 11:23 AM, Claudiu wrote:
>
>> From: Claudiu Beznea <[email protected]>
>>
>> The runtime PM implementation will disable clocks at the end of
>> ravb_probe(). As some IP variants switch to reset mode as a result of
>> setting module standby through clock disable APIs, to implement runtime PM
>> the resource parsing and requesting are moved in the probe function and IP
>> settings are moved in the open function. This is done because at the end of
>> the probe some IP variants will switch anyway to reset mode and the
>> registers content is lost. Also keeping only register specific operations
>> in the ravb_open()/ravb_close() functions will make them faster.
>>
>> Commit moves IRQ requests to ravb_probe() to have all the IRQs ready when
>> the interface is open. As now IRQs gets and requests are in a single place
>> there is no need to keep intermediary data (like ravb_rx_irqs[] and
>> ravb_tx_irqs[] arrays or IRQs in struct ravb_private).
>
> There's one thing that you probably didn't take into account: after
> you call request_irq(), you should be able to handle your IRQ as it's
> automatically unmasked, unless you pass IRQF_NO_AUTOEN to request_irq().
> Your device may be held i reset or even powered off but if you pass IRQF_SHARED to request_irq() (you do in a single IRQ config), you must
> be prepared to get your device's registers read (in order to ascertain
> whether it's your IRQ or not). And you can't even pass IRQF_NO_AUTOEN
> along with IRQF_SHARED, according to my reading of the IRQ code...
Good point!
>
>> This is a preparatory change to add runtime PM support for all IP variants.
>
> I don't readily see why this is necessary for the full-fledged RPM
> support...
I tried to speed up the ravb_open()/ravb_close() but missed the IRQF_SHARED
IRQ. As there is only one IRQ requested w/ IRQF_SHARED, are you OK with
still keeping the rest of IRQs handled as proposed by this patch?
>
>> Signed-off-by: Claudiu Beznea <[email protected]>
>
> Unfortunately, I have to NAK this patch, at least in its current
> form...
>
> [...]
>
> MBR, Sergey
On 1/5/24 11:23 AM, Claudiu wrote:
> From: Claudiu Beznea <[email protected]>
>
> As some IP variants switch to reset mode (and thus registers content is
> lost) when setting clocks (due to module standby functionality) to be able
> to implement runtime PM and save more power, set the IP's operating mode to
> reset at the end of the probe. Along with it, in the ndo_open API the IP
> will be switched to configuration, then operation mode. In the ndo_close
> API, the IP will be switched back to reset mode. This allows implementing
> runtime PM and, along with it, save more power when the IP is not used.
>
> Signed-off-by: Claudiu Beznea <[email protected]>
> ---
>
> Changes in v3:
> - fixed typos in patch description
> - in ravb_probe() switch the hardware to reset mode just after phy
> initialization
>
> Changes in v2:
> - none; this patch is new
>
>
> drivers/net/ethernet/renesas/ravb_main.c | 78 ++++++++++++++----------
> 1 file changed, 46 insertions(+), 32 deletions(-)
>
> diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
> index 1cc1ecd8d6a8..434b4777de5e 100644
> --- a/drivers/net/ethernet/renesas/ravb_main.c
> +++ b/drivers/net/ethernet/renesas/ravb_main.c
[...]
> @@ -2746,11 +2755,6 @@ static int ravb_probe(struct platform_device *pdev)
> ndev->netdev_ops = &ravb_netdev_ops;
> ndev->ethtool_ops = &ravb_ethtool_ops;
>
> - /* Set AVB config mode */
> - error = ravb_set_config_mode(ndev);
> - if (error)
> - goto out_rpm_put;
> -
> error = ravb_compute_gti(ndev);
> if (error)
> goto out_rpm_put;
> @@ -2785,13 +2789,23 @@ static int ravb_probe(struct platform_device *pdev)
> eth_hw_addr_random(ndev);
> }
>
> + /* Set config mode as this is needed for PHY initialization. */
> + error = ravb_set_opmode(ndev, CCC_OPC_CONFIG);
Hm... don't you need this at laest before calling ravb_read_mac_address()
just above?
> + if (error)
> + goto out_rpm_put;
> +
> /* MDIO bus init */
> error = ravb_mdio_init(priv);
> if (error) {
> dev_err(&pdev->dev, "failed to initialize MDIO\n");
> - goto out_dma_free;
> + goto out_reset_mode;
> }
>
> + /* Undo previous switch to config opmode. */
> + error = ravb_set_opmode(ndev, CCC_OPC_RESET);
> + if (error)
> + goto out_mdio_release;
> +
> netif_napi_add(ndev, &priv->napi[RAVB_BE], ravb_poll);
> if (info->nc_queues)
> netif_napi_add(ndev, &priv->napi[RAVB_NC], ravb_poll);
[...]
MBR, Sergey
On 1/5/24 11:23 AM, Claudiu wrote:
> From: Claudiu Beznea <[email protected]>
>
> Return the cached statistics in case the interface is down. There should be
> no drawback to this, as cached statistics are updated in ravb_close().
>
> The commit prepares the code for the addition of runtime PM support.
>
> Suggested-by: Sergey Shtylyov <[email protected]>
> Signed-off-by: Claudiu Beznea <[email protected]>
[...]
> diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
> index 76035afd4054..168b6208db37 100644
> --- a/drivers/net/ethernet/renesas/ravb_main.c
> +++ b/drivers/net/ethernet/renesas/ravb_main.c
> @@ -2117,6 +2117,9 @@ static struct net_device_stats *ravb_get_stats(struct net_device *ndev)
> const struct ravb_hw_info *info = priv->info;
> struct net_device_stats *nstats, *stats0, *stats1;
>
> + if (!(ndev->flags & IFF_UP))
Well, I guess it's OK to read the counters in the reset mode... BUT
won't this race with pm_runtime_put_autosuspend() when its call gets added
to ravb_close()?
> + return &ndev->stats;
> +
> nstats = &ndev->stats;
> stats0 = &priv->stats[RAVB_BE];
>
[...]
MBR, Sergey
On 1/5/24 11:23 AM, Claudiu wrote:
> From: Claudiu Beznea <[email protected]>
>
> Do not apply the RX CSUM settings to hardware if the interface is down. In
> case runtime PM is enabled, and while the interface is down, the IP will be
> in reset mode (as for some platforms disabling the clocks will switch the
> IP to reset mode, which will lead to losing registers content) and applying
> settings in reset mode is not an option. Instead, cache the RX CSUM
> settings and apply them in ravb_open() though ravb_emac_init().
>
> Commit prepares for the addition of runtime PM.
>
> Signed-off-by: Claudiu Beznea <[email protected]>
[...]
> diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
> index 168b6208db37..e909960fbc30 100644
> --- a/drivers/net/ethernet/renesas/ravb_main.c
> +++ b/drivers/net/ethernet/renesas/ravb_main.c
> @@ -2342,6 +2342,9 @@ static void ravb_set_rx_csum(struct net_device *ndev, bool enable)
> struct ravb_private *priv = netdev_priv(ndev);
> unsigned long flags;
>
> + if (!(ndev->flags & IFF_UP))
Well, I guess it's even OK to even write EDCMR in the reset mode... BUT
again, won't this race with pm_runtime_put_autosuspend() when its call gets
added to ravb_close()?
> + return;
> +
> spin_lock_irqsave(&priv->lock, flags);
>
> /* Disable TX and RX */
MBR, Sergey
On 1/8/24 11:34 PM, Sergey Shtylyov wrote:
[...]
>> From: Claudiu Beznea <[email protected]>
>>
>> Do not apply the RX CSUM settings to hardware if the interface is down. In
>> case runtime PM is enabled, and while the interface is down, the IP will be
>> in reset mode (as for some platforms disabling the clocks will switch the
>> IP to reset mode, which will lead to losing registers content) and applying
>> settings in reset mode is not an option. Instead, cache the RX CSUM
>> settings and apply them in ravb_open() though ravb_emac_init().
>>
>> Commit prepares for the addition of runtime PM.
>>
>> Signed-off-by: Claudiu Beznea <[email protected]>
> [...]
>
>> diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
>> index 168b6208db37..e909960fbc30 100644
>> --- a/drivers/net/ethernet/renesas/ravb_main.c
>> +++ b/drivers/net/ethernet/renesas/ravb_main.c
>> @@ -2342,6 +2342,9 @@ static void ravb_set_rx_csum(struct net_device *ndev, bool enable)
>> struct ravb_private *priv = netdev_priv(ndev);
>> unsigned long flags;
>>
>> + if (!(ndev->flags & IFF_UP))
>
> Well, I guess it's even OK to even write EDCMR in the reset mode... BUT
Well, I guess it's even OK to write ECMR in the reset mode... :-)
> again, won't this race with pm_runtime_put_autosuspend() when its call gets
> added to ravb_close()?
[...]
MBR, Sergey
On 1/5/24 11:23 AM, Claudiu wrote:
> From: Claudiu Beznea <[email protected]>
>
> Do not apply the RX CSUM settings to hardware if the interface is down. In
s/CSUM/checksum/?
> case runtime PM is enabled, and while the interface is down, the IP will be
> in reset mode (as for some platforms disabling the clocks will switch the
> IP to reset mode, which will lead to losing registers content) and applying
> settings in reset mode is not an option. Instead, cache the RX CSUM
Same here...
> settings and apply them in ravb_open() though ravb_emac_init().
Through?
> Commit prepares for the addition of runtime PM.
>
> Signed-off-by: Claudiu Beznea <[email protected]>
[...]
MBR, Sergey
On 08.01.2024 21:28, Sergey Shtylyov wrote:
> On 1/5/24 11:23 AM, Claudiu wrote:
>
>> From: Claudiu Beznea <[email protected]>
>>
>> As some IP variants switch to reset mode (and thus registers content is
>> lost) when setting clocks (due to module standby functionality) to be able
>> to implement runtime PM and save more power, set the IP's operating mode to
>> reset at the end of the probe. Along with it, in the ndo_open API the IP
>> will be switched to configuration, then operation mode. In the ndo_close
>> API, the IP will be switched back to reset mode. This allows implementing
>> runtime PM and, along with it, save more power when the IP is not used.
>>
>> Signed-off-by: Claudiu Beznea <[email protected]>
>> ---
>>
>> Changes in v3:
>> - fixed typos in patch description
>> - in ravb_probe() switch the hardware to reset mode just after phy
>> initialization
>>
>> Changes in v2:
>> - none; this patch is new
>>
>>
>> drivers/net/ethernet/renesas/ravb_main.c | 78 ++++++++++++++----------
>> 1 file changed, 46 insertions(+), 32 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
>> index 1cc1ecd8d6a8..434b4777de5e 100644
>> --- a/drivers/net/ethernet/renesas/ravb_main.c
>> +++ b/drivers/net/ethernet/renesas/ravb_main.c
> [...]
>> @@ -2746,11 +2755,6 @@ static int ravb_probe(struct platform_device *pdev)
>> ndev->netdev_ops = &ravb_netdev_ops;
>> ndev->ethtool_ops = &ravb_ethtool_ops;
>>
>> - /* Set AVB config mode */
>> - error = ravb_set_config_mode(ndev);
>> - if (error)
>> - goto out_rpm_put;
>> -
>> error = ravb_compute_gti(ndev);
>> if (error)
>> goto out_rpm_put;
>> @@ -2785,13 +2789,23 @@ static int ravb_probe(struct platform_device *pdev)
>> eth_hw_addr_random(ndev);
>> }
>>
>> + /* Set config mode as this is needed for PHY initialization. */
>> + error = ravb_set_opmode(ndev, CCC_OPC_CONFIG);
>
> Hm... don't you need this at laest before calling ravb_read_mac_address()
> just above?
I asked myself this, haven't experienced issues w/ it while working on this
patch thus I kept it as is. In theory, yes, it should be above that call.
I'll move it there.
Thank you,
Claudiu Beznea
>
>> + if (error)
>> + goto out_rpm_put;
>> +
>> /* MDIO bus init */
>> error = ravb_mdio_init(priv);
>> if (error) {
>> dev_err(&pdev->dev, "failed to initialize MDIO\n");
>> - goto out_dma_free;
>> + goto out_reset_mode;
>> }
>>
>> + /* Undo previous switch to config opmode. */
>> + error = ravb_set_opmode(ndev, CCC_OPC_RESET);
>> + if (error)
>> + goto out_mdio_release;
>> +
>> netif_napi_add(ndev, &priv->napi[RAVB_BE], ravb_poll);
>> if (info->nc_queues)
>> netif_napi_add(ndev, &priv->napi[RAVB_NC], ravb_poll);
> [...]
>
> MBR, Sergey
On 1/5/24 11:23 AM, Claudiu wrote:
> From: Claudiu Beznea <[email protected]>
>
> Add runtime PM support for the ravb driver. As the driver is used by
> different IP variants, with different behaviors, to be able to have the
> runtime PM support available for all devices, the preparatory commits
> moved all the resources parsing and allocations in the driver's probe
> function and kept the settings for ravb_open(). This is due to the fact
> that on some IP variants-platforms tuples disabling/enabling the clocks
> will switch the IP to the reset operation mode where registers' content is
> lost and reconfiguration needs to be done. For this the rabv_open()
> function enables the clocks, switches the IP to configuration mode, applies
> all the registers settings and switches the IP to the operational mode. At
> the end of ravb_open() IP is ready to send/receive data.
>
> In ravb_close() necessary reverts are done (compared with ravb_open()), the
> IP is switched to reset mode and clocks are disabled.
>
> The ethtool APIs or IOCTLs that might execute while the interface is down
> are either cached (and applied in ravb_open()) or rejected (as at that time
> the IP is in reset mode). Keeping the IP in the reset mode also increases
> the power saved (according to the hardware manual).
>
> Reviewed-by: Sergey Shtylyov <[email protected]>
> Signed-off-by: Claudiu Beznea <[email protected]>
[...]
> diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
> index e909960fbc30..e99351fe8d7f 100644
> --- a/drivers/net/ethernet/renesas/ravb_main.c
> +++ b/drivers/net/ethernet/renesas/ravb_main.c
[...]
> @@ -2233,7 +2243,14 @@ static int ravb_close(struct net_device *ndev)
> ravb_get_stats(ndev);
>
> /* Set reset mode. */
> - return ravb_set_opmode(ndev, CCC_OPC_RESET);
> + error = ravb_set_opmode(ndev, CCC_OPC_RESET);
> + if (error)
> + return error;
> +
> + pm_runtime_mark_last_busy(dev);
> + pm_runtime_put_autosuspend(dev);
BTW, doesn't make sense to check/return the result?
> +
> + return 0;
> }
>
> static int ravb_hwtstamp_get(struct net_device *ndev, struct ifreq *req)
[...]
MBR, Sergey
On 1/8/24 11:58 AM, claudiu beznea wrote:
[...]
>>> From: Claudiu Beznea <[email protected]>
>>>
>>> The runtime PM implementation will disable clocks at the end of
>>> ravb_probe(). As some IP variants switch to reset mode as a result of
>>> setting module standby through clock disable APIs, to implement runtime PM
>>> the resource parsing and requesting are moved in the probe function and IP
>>> settings are moved in the open function. This is done because at the end of
>>> the probe some IP variants will switch anyway to reset mode and the
>>> registers content is lost. Also keeping only register specific operations
>>> in the ravb_open()/ravb_close() functions will make them faster.
>>>
>>> Commit moves IRQ requests to ravb_probe() to have all the IRQs ready when
>>> the interface is open. As now IRQs gets and requests are in a single place
>>> there is no need to keep intermediary data (like ravb_rx_irqs[] and
>>> ravb_tx_irqs[] arrays or IRQs in struct ravb_private).
>>
>> There's one thing that you probably didn't take into account: after
>> you call request_irq(), you should be able to handle your IRQ as it's
>> automatically unmasked, unless you pass IRQF_NO_AUTOEN to request_irq().
>> Your device may be held i reset or even powered off but if you pass IRQF_SHARED to request_irq() (you do in a single IRQ config), you must
>> be prepared to get your device's registers read (in order to ascertain
And, at least on arm32, reading a powered off (or not clocked?) device's
register causes an imprecise external abort exception -- which results in a
kernel oops...
>> whether it's your IRQ or not). And you can't even pass IRQF_NO_AUTOEN
>> along with IRQF_SHARED, according to my reading of the IRQ code...
>
> Good point!
>
>>> This is a preparatory change to add runtime PM support for all IP variants.
>>
>> I don't readily see why this is necessary for the full-fledged RPM
>> support...
>
> I tried to speed up the ravb_open()/ravb_close() but missed the IRQF_SHARED
I doubt that optimizing ravb_{open,close}() is worth pursuing, frankly...
> IRQ. As there is only one IRQ requested w/ IRQF_SHARED, are you OK with
> still keeping the rest of IRQs handled as proposed by this patch?
I'm not, as this doesn't really seem necessary for your main goal.
It's not clear in what state U-Boot leaves EtherAVB...
[...]
MBR, Sergey
On 09.01.2024 22:47, Sergey Shtylyov wrote:
> On 1/8/24 11:58 AM, claudiu beznea wrote:
>
> [...]
>>>> From: Claudiu Beznea <[email protected]>
>>>>
>>>> The runtime PM implementation will disable clocks at the end of
>>>> ravb_probe(). As some IP variants switch to reset mode as a result of
>>>> setting module standby through clock disable APIs, to implement runtime PM
>>>> the resource parsing and requesting are moved in the probe function and IP
>>>> settings are moved in the open function. This is done because at the end of
>>>> the probe some IP variants will switch anyway to reset mode and the
>>>> registers content is lost. Also keeping only register specific operations
>>>> in the ravb_open()/ravb_close() functions will make them faster.
>>>>
>>>> Commit moves IRQ requests to ravb_probe() to have all the IRQs ready when
>>>> the interface is open. As now IRQs gets and requests are in a single place
>>>> there is no need to keep intermediary data (like ravb_rx_irqs[] and
>>>> ravb_tx_irqs[] arrays or IRQs in struct ravb_private).
>>>
>>> There's one thing that you probably didn't take into account: after
>>> you call request_irq(), you should be able to handle your IRQ as it's
>>> automatically unmasked, unless you pass IRQF_NO_AUTOEN to request_irq().
>>> Your device may be held i reset or even powered off but if you pass IRQF_SHARED to request_irq() (you do in a single IRQ config), you must
>>> be prepared to get your device's registers read (in order to ascertain
>
> And, at least on arm32, reading a powered off (or not clocked?) device's
> register causes an imprecise external abort exception -- which results in a
> kernel oops...
>
>>> whether it's your IRQ or not). And you can't even pass IRQF_NO_AUTOEN
>>> along with IRQF_SHARED, according to my reading of the IRQ code...
>>
>> Good point!
>>
>>>> This is a preparatory change to add runtime PM support for all IP variants.
>>>
>>> I don't readily see why this is necessary for the full-fledged RPM
>>> support...
>>
>> I tried to speed up the ravb_open()/ravb_close() but missed the IRQF_SHARED
>
> I doubt that optimizing ravb_{open,close}() is worth pursuing, frankly...
>
>> IRQ. As there is only one IRQ requested w/ IRQF_SHARED, are you OK with
>> still keeping the rest of IRQs handled as proposed by this patch?
>
> I'm not, as this doesn't really seem necessary for your main goal.
> It's not clear in what state U-Boot leaves EtherAVB...
Ok. One other reason I did this is, as commit message states, to keep
resource parsing and allocation/freeing in probe/remove and hardware
settings in open/close.
Anyway, I'll revert all the changes IRQ related.
Thank you,
Claudiu Beznea
>
> [...]
>
> MBR, Sergey
On 08.01.2024 22:22, Sergey Shtylyov wrote:
> On 1/5/24 11:23 AM, Claudiu wrote:
>
>> From: Claudiu Beznea <[email protected]>
>>
>> Return the cached statistics in case the interface is down. There should be
>> no drawback to this, as cached statistics are updated in ravb_close().
>>
>> The commit prepares the code for the addition of runtime PM support.
>>
>> Suggested-by: Sergey Shtylyov <[email protected]>
>> Signed-off-by: Claudiu Beznea <[email protected]>
> [...]
>
>> diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
>> index 76035afd4054..168b6208db37 100644
>> --- a/drivers/net/ethernet/renesas/ravb_main.c
>> +++ b/drivers/net/ethernet/renesas/ravb_main.c
>> @@ -2117,6 +2117,9 @@ static struct net_device_stats *ravb_get_stats(struct net_device *ndev)
>> const struct ravb_hw_info *info = priv->info;
>> struct net_device_stats *nstats, *stats0, *stats1;
>>
>> + if (!(ndev->flags & IFF_UP))
>
> Well, I guess it's OK to read the counters in the reset mode... BUT
> won't this race with pm_runtime_put_autosuspend() when its call gets added
> to ravb_close()?
I re-checked it and, yes, this is true. A sync runtime suspend would be
better here. But, as of my current investigation, even with this
ravb_get_stats() can still race with ravb_open()/ravb_close() as they are
called though different locking scheme (ravb_open()/ravb_close() is called
with rtnl locked while ravb_get_stats() can be called only with
dev_base_lock rwlock locked for reading).
A mutex in the driver should to help with this.
Thank you,
Claudiu Beznea
>
>> + return &ndev->stats;
>> +
>> nstats = &ndev->stats;
>> stats0 = &priv->stats[RAVB_BE];
>>
> [...]
>
> MBR, Sergey
>
On 09.01.2024 21:53, Sergey Shtylyov wrote:
> On 1/5/24 11:23 AM, Claudiu wrote:
>
>> From: Claudiu Beznea <[email protected]>
>>
>> Add runtime PM support for the ravb driver. As the driver is used by
>> different IP variants, with different behaviors, to be able to have the
>> runtime PM support available for all devices, the preparatory commits
>> moved all the resources parsing and allocations in the driver's probe
>> function and kept the settings for ravb_open(). This is due to the fact
>> that on some IP variants-platforms tuples disabling/enabling the clocks
>> will switch the IP to the reset operation mode where registers' content is
>> lost and reconfiguration needs to be done. For this the rabv_open()
>> function enables the clocks, switches the IP to configuration mode, applies
>> all the registers settings and switches the IP to the operational mode. At
>> the end of ravb_open() IP is ready to send/receive data.
>>
>> In ravb_close() necessary reverts are done (compared with ravb_open()), the
>> IP is switched to reset mode and clocks are disabled.
>>
>> The ethtool APIs or IOCTLs that might execute while the interface is down
>> are either cached (and applied in ravb_open()) or rejected (as at that time
>> the IP is in reset mode). Keeping the IP in the reset mode also increases
>> the power saved (according to the hardware manual).
>>
>> Reviewed-by: Sergey Shtylyov <[email protected]>
>> Signed-off-by: Claudiu Beznea <[email protected]>
> [...]
>
>> diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
>> index e909960fbc30..e99351fe8d7f 100644
>> --- a/drivers/net/ethernet/renesas/ravb_main.c
>> +++ b/drivers/net/ethernet/renesas/ravb_main.c
> [...]
>> @@ -2233,7 +2243,14 @@ static int ravb_close(struct net_device *ndev)
>> ravb_get_stats(ndev);
>>
>> /* Set reset mode. */
>> - return ravb_set_opmode(ndev, CCC_OPC_RESET);
>> + error = ravb_set_opmode(ndev, CCC_OPC_RESET);
>> + if (error)
>> + return error;
>> +
>> + pm_runtime_mark_last_busy(dev);
>> + pm_runtime_put_autosuspend(dev);
>
> BTW, doesn't make sense to check/return the result?
Most users of this are not checking return code, I followed this pattern,
too. But, yes, would be better to check it, AFAICT.
>
>> +
>> + return 0;
>> }
>>
>> static int ravb_hwtstamp_get(struct net_device *ndev, struct ifreq *req)
> [...]
>
> MBR, Sergey
On 1/10/24 4:17 PM, claudiu beznea wrote:
[...]
>>> From: Claudiu Beznea <[email protected]>
>>>
>>> Return the cached statistics in case the interface is down. There should be
>>> no drawback to this, as cached statistics are updated in ravb_close().
>>>
>>> The commit prepares the code for the addition of runtime PM support.
>>>
>>> Suggested-by: Sergey Shtylyov <[email protected]>
>>> Signed-off-by: Claudiu Beznea <[email protected]>
>> [...]
>>
>>> diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
>>> index 76035afd4054..168b6208db37 100644
>>> --- a/drivers/net/ethernet/renesas/ravb_main.c
>>> +++ b/drivers/net/ethernet/renesas/ravb_main.c
>>> @@ -2117,6 +2117,9 @@ static struct net_device_stats *ravb_get_stats(struct net_device *ndev)
>>> const struct ravb_hw_info *info = priv->info;
>>> struct net_device_stats *nstats, *stats0, *stats1;
>>>
>>> + if (!(ndev->flags & IFF_UP))
>>
>> Well, I guess it's OK to read the counters in the reset mode... BUT
>> won't this race with pm_runtime_put_autosuspend() when its call gets added
>> to ravb_close()?
>
> I re-checked it and, yes, this is true. A sync runtime suspend would be
> better here. But, as of my current investigation, even with this
No, the sync form of the RPM call won't fix the race...
> ravb_get_stats() can still race with ravb_open()/ravb_close() as they are
> called though different locking scheme (ravb_open()/ravb_close() is called
> with rtnl locked while ravb_get_stats() can be called only with
> dev_base_lock rwlock locked for reading).
>
> A mutex in the driver should to help with this.
Why don't you want to mimic what the sh_eth driver does?
> Thank you,
> Claudiu Beznea
[...]
MBR, Sergey
On 1/10/24 2:55 PM, claudiu beznea wrote:
[...]
>>>>> From: Claudiu Beznea <[email protected]>
>>>>>
>>>>> The runtime PM implementation will disable clocks at the end of
>>>>> ravb_probe(). As some IP variants switch to reset mode as a result of
>>>>> setting module standby through clock disable APIs, to implement runtime PM
>>>>> the resource parsing and requesting are moved in the probe function and IP
>>>>> settings are moved in the open function. This is done because at the end of
>>>>> the probe some IP variants will switch anyway to reset mode and the
>>>>> registers content is lost. Also keeping only register specific operations
>>>>> in the ravb_open()/ravb_close() functions will make them faster.
>>>>>
>>>>> Commit moves IRQ requests to ravb_probe() to have all the IRQs ready when
>>>>> the interface is open. As now IRQs gets and requests are in a single place
>>>>> there is no need to keep intermediary data (like ravb_rx_irqs[] and
>>>>> ravb_tx_irqs[] arrays or IRQs in struct ravb_private).
>>>>
>>>> There's one thing that you probably didn't take into account: after
>>>> you call request_irq(), you should be able to handle your IRQ as it's
>>>> automatically unmasked, unless you pass IRQF_NO_AUTOEN to request_irq().
>>>> Your device may be held i reset or even powered off but if you pass
>>>> IRQF_SHARED to request_irq() (you do in a single IRQ config), you must
>>>> be prepared to get your device's registers read (in order to ascertain
>>
>> And, at least on arm32, reading a powered off (or not clocked?) device's
>> register causes an imprecise external abort exception -- which results in a
>> kernel oops...
>>
>>>> whether it's your IRQ or not). And you can't even pass IRQF_NO_AUTOEN
>>>> along with IRQF_SHARED, according to my reading of the IRQ code...
>>>
>>> Good point!
Iff we can come up with a robust check whether the device is powered on,
we can overcome even the IRQF_SHARED issue though...
I'm seeing pm_runtime_active() API and wondering whether we can use it
from the IRQ context. Alternatively, we can add a is_opened flag, like
sh_eth.c does...
>>>>> This is a preparatory change to add runtime PM support for all IP variants.
>>>>
>>>> I don't readily see why this is necessary for the full-fledged RPM
>>>> support...
>>>
>>> I tried to speed up the ravb_open()/ravb_close() but missed the IRQF_SHARED
>>
>> I doubt that optimizing ravb_{open,close}() is worth pursuing, frankly...
OTOH, we'll get a simpler/cleaner code if we do this...
Previously, I was under an impression that it's common behavior of
the networking drivers to call request_irq() from their ndo_open() methods.
Apparently, it's not true anymore (probably with the introduction of the
managed device API) -- the newer drivers often call devm_request_irq()
from their probe() methods instead...
>>> IRQ. As there is only one IRQ requested w/ IRQF_SHARED, are you OK with
>>> still keeping the rest of IRQs handled as proposed by this patch?
>>
>> I'm not, as this doesn't really seem necessary for your main goal.
>> It's not clear in what state U-Boot leaves EtherAVB...
This still seems an issue though... My prior experience with the R-Car
MMC driver tells me that U-Boot may leave interrupts enabled... :-/
> Ok. One other reason I did this is, as commit message states, to keep
> resource parsing and allocation/freeing in probe/remove and hardware
> settings in open/close.
>
> Anyway, I'll revert all the changes IRQ related.
Now I've changed my mind -- let's retain your patch! It needs some work
though...
> Thank you,
> Claudiu Beznea
[...]
MBR, Sergey
On 14.01.2024 14:22, Sergey Shtylyov wrote:
> On 1/10/24 4:17 PM, claudiu beznea wrote:
>
> [...]
>
>>>> From: Claudiu Beznea <[email protected]>
>>>>
>>>> Return the cached statistics in case the interface is down. There should be
>>>> no drawback to this, as cached statistics are updated in ravb_close().
>>>>
>>>> The commit prepares the code for the addition of runtime PM support.
>>>>
>>>> Suggested-by: Sergey Shtylyov <[email protected]>
>>>> Signed-off-by: Claudiu Beznea <[email protected]>
>>> [...]
>>>
>>>> diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
>>>> index 76035afd4054..168b6208db37 100644
>>>> --- a/drivers/net/ethernet/renesas/ravb_main.c
>>>> +++ b/drivers/net/ethernet/renesas/ravb_main.c
>>>> @@ -2117,6 +2117,9 @@ static struct net_device_stats *ravb_get_stats(struct net_device *ndev)
>>>> const struct ravb_hw_info *info = priv->info;
>>>> struct net_device_stats *nstats, *stats0, *stats1;
>>>>
>>>> + if (!(ndev->flags & IFF_UP))
>>>
>>> Well, I guess it's OK to read the counters in the reset mode... BUT
>>> won't this race with pm_runtime_put_autosuspend() when its call gets added
>>> to ravb_close()?
>>
>> I re-checked it and, yes, this is true. A sync runtime suspend would be
>> better here. But, as of my current investigation, even with this
>
> No, the sync form of the RPM call won't fix the race...
>
>> ravb_get_stats() can still race with ravb_open()/ravb_close() as they are
>> called though different locking scheme (ravb_open()/ravb_close() is called
>> with rtnl locked while ravb_get_stats() can be called only with
>> dev_base_lock rwlock locked for reading).
>>
>> A mutex in the driver should to help with this.
>
> Why don't you want to mimic what the sh_eth driver does?
I thought it can be replaced by the already existing IFF_UP flag from
ndev->flags.
Investigating it further while trying to address this concurrency issue
made me realize that it fits to address the issue you mentioned here.
Thank you,
Claudiu Beznea
>
>> Thank you,
>> Claudiu Beznea
>
> [...]
>
> MBR, Sergey
On 14.01.2024 20:07, Sergey Shtylyov wrote:
> On 1/10/24 2:55 PM, claudiu beznea wrote:
>
> [...]
>
>>>>>> From: Claudiu Beznea <[email protected]>
>>>>>>
>>>>>> The runtime PM implementation will disable clocks at the end of
>>>>>> ravb_probe(). As some IP variants switch to reset mode as a result of
>>>>>> setting module standby through clock disable APIs, to implement runtime PM
>>>>>> the resource parsing and requesting are moved in the probe function and IP
>>>>>> settings are moved in the open function. This is done because at the end of
>>>>>> the probe some IP variants will switch anyway to reset mode and the
>>>>>> registers content is lost. Also keeping only register specific operations
>>>>>> in the ravb_open()/ravb_close() functions will make them faster.
>>>>>>
>>>>>> Commit moves IRQ requests to ravb_probe() to have all the IRQs ready when
>>>>>> the interface is open. As now IRQs gets and requests are in a single place
>>>>>> there is no need to keep intermediary data (like ravb_rx_irqs[] and
>>>>>> ravb_tx_irqs[] arrays or IRQs in struct ravb_private).
>>>>>
>>>>> There's one thing that you probably didn't take into account: after
>>>>> you call request_irq(), you should be able to handle your IRQ as it's
>>>>> automatically unmasked, unless you pass IRQF_NO_AUTOEN to request_irq().
>>>>> Your device may be held i reset or even powered off but if you pass
>>>>> IRQF_SHARED to request_irq() (you do in a single IRQ config), you must
>>>>> be prepared to get your device's registers read (in order to ascertain
>>>
>>> And, at least on arm32, reading a powered off (or not clocked?) device's
>>> register causes an imprecise external abort exception -- which results in a
>>> kernel oops...
>>>
>>>>> whether it's your IRQ or not). And you can't even pass IRQF_NO_AUTOEN
>>>>> along with IRQF_SHARED, according to my reading of the IRQ code...
>>>>
>>>> Good point!
>
> Iff we can come up with a robust check whether the device is powered on,
> we can overcome even the IRQF_SHARED issue though...
> I'm seeing pm_runtime_active() API and wondering whether we can use it
> from the IRQ context. Alternatively, we can add a is_opened flag, like
> sh_eth.c does...
The is_open flag should deal with this, too, AFAICT at the moment, and
should also cover your concerns about U-Boot.
Thank you,
Claudiu Beznea
>
>>>>>> This is a preparatory change to add runtime PM support for all IP variants.
>>>>>
>>>>> I don't readily see why this is necessary for the full-fledged RPM
>>>>> support...
>>>>
>>>> I tried to speed up the ravb_open()/ravb_close() but missed the IRQF_SHARED
>>>
>>> I doubt that optimizing ravb_{open,close}() is worth pursuing, frankly...
>
> OTOH, we'll get a simpler/cleaner code if we do this...
> Previously, I was under an impression that it's common behavior of
> the networking drivers to call request_irq() from their ndo_open() methods.
> Apparently, it's not true anymore (probably with the introduction of the
> managed device API) -- the newer drivers often call devm_request_irq()
> from their probe() methods instead...
>
>>>> IRQ. As there is only one IRQ requested w/ IRQF_SHARED, are you OK with
>>>> still keeping the rest of IRQs handled as proposed by this patch?
>>>
>>> I'm not, as this doesn't really seem necessary for your main goal.
>>> It's not clear in what state U-Boot leaves EtherAVB...
>
> This still seems an issue though... My prior experience with the R-Car
> MMC driver tells me that U-Boot may leave interrupts enabled... :-/
>
>> Ok. One other reason I did this is, as commit message states, to keep
>> resource parsing and allocation/freeing in probe/remove and hardware
>> settings in open/close.
>>
>> Anyway, I'll revert all the changes IRQ related.
>
> Now I've changed my mind -- let's retain your patch! It needs some work
> though...
>
>> Thank you,
>> Claudiu Beznea
>
> [...]
>
> MBR, Sergey
On 1/8/24 11:03 AM, claudiu beznea wrote:
Oops, looks like I forgot to reply to this one...
[...]
>>> From: Claudiu Beznea <[email protected]>
>>>
>>> Reference clock could be or not part of the power domain. If it is part of
>>> the power domain, the power domain takes care of propertly setting it. In
>>> case it is not part of the power domain and full runtime PM support is
>>> available in driver the clock will not be propertly disabled/enabled at
>>> runtime. For this, keep the prepare/unprepare operations in the driver's
>>> probe()/remove() functions and move the enable/disable in runtime PM
>>> functions.
>>>
>>> Along with it, the other clock request operations were moved close to
>>> reference clock request and prepare to have all the clock requests
>>> specific code grouped together.
>>>
>>> Reviewed-by: Sergey Shtylyov <[email protected]>
[...]
>>> Signed-off-by: Claudiu Beznea <[email protected]>
[...]
>>> diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
>>> index 844ac3306e93..4673cc2faec0 100644
>>> --- a/drivers/net/ethernet/renesas/ravb_main.c
>>> +++ b/drivers/net/ethernet/renesas/ravb_main.c
[...]
>>> + pm_runtime_enable(&pdev->dev);
>>> + error = pm_runtime_resume_and_get(&pdev->dev);
>>> + if (error < 0)
>>> + goto out_rpm_disable;
>>> +
>>> priv->addr = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
>>> if (IS_ERR(priv->addr)) {
>>> error = PTR_ERR(priv->addr);
>>> - goto out_release;
>>> + goto out_rpm_put;
>>> }
>>>
>>> /* The Ether-specific entries in the device structure. */
[...]
>>> @@ -3060,21 +3058,27 @@ static int ravb_resume(struct device *dev)
>>> return ret;
>>> }
>>>
>>> -static int ravb_runtime_nop(struct device *dev)
>>> +static int ravb_runtime_suspend(struct device *dev)
>>> {
>>> - /* Runtime PM callback shared between ->runtime_suspend()
>>> - * and ->runtime_resume(). Simply returns success.
>>> - *
>>> - * This driver re-initializes all registers after
>>> - * pm_runtime_get_sync() anyway so there is no need
>>> - * to save and restore registers here.
>>> - */
>>
>> Perhaps even worth a separate patch to completely remove this function
>> which doesn't seem to make sense?
>
> Why? With that the refclk will not be properly enabled/disabled when it
> will not be part of the power domain. Take
That's what you are adding in this patch, right? Before this patch
this was ravb_runtime_nop(), always returning 0. Did it make any sense?
> https://elixir.bootlin.com/linux/v6.7/source/arch/arm64/boot/dts/renesas/beacon-renesom-som.dtsi#L57
> as an example. Here refclk is from an external source (not part of power
> domain).
>
> Thank you,
> Claudiu Beznea
[...]
MBR, Sergey