[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <6e3435a0-b04e-44cc-9e9d-981a8e9c3165@lunn.ch>
Date: Thu, 8 May 2025 16:44:55 +0200
From: Andrew Lunn <andrew@...n.ch>
To: Asmaa Mnebhi <asmaa@...dia.com>
Cc: "davem@...emloft.net" <davem@...emloft.net>,
"edumazet@...gle.com" <edumazet@...gle.com>,
"kuba@...nel.org" <kuba@...nel.org>,
"pabeni@...hat.com" <pabeni@...hat.com>,
"netdev@...r.kernel.org" <netdev@...r.kernel.org>,
"linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>,
David Thompson <davthompson@...dia.com>
Subject: Re: [PATCH net v1] mlxbf-gige: Support workaround for MDIO GPIO
degradation bug
> > My reading of this is that you can stop the clock when it is not needed. Maybe
> > tie into the Linux runtime power management framework. It can keep track of
> > how long a device has been idle, and if a timer is exceeded, make a callback to
> > power it down.
> >
> > If you have an MDIO bus with one PHY on it, the access pattern is likely to be a
> > small bunch of reads followed by about one second of idle time. I would of
> > thought that stopping the clock increases the life expectancy of you hardware
> > more than just slowing it down.
>
> Hi Andrew,
>
> Thank you for your answer and apologies for the very late
> response. My concern with completely stopping the clock is the case
> we are using the PHY polling mode for the link status? We would need
> MDIO to always be operational for polling to work, wouldn't we?
You should look at how power management work. For example, in the FEC
driver:
https://elixir.bootlin.com/linux/v6.14.5/source/drivers/net/ethernet/freescale/fec_main.c#L2180
static int fec_enet_mdio_read_c22(struct mii_bus *bus, int mii_id, int regnum)
{
struct fec_enet_private *fep = bus->priv;
struct device *dev = &fep->pdev->dev;
int ret = 0, frame_start, frame_addr, frame_op;
ret = pm_runtime_resume_and_get(dev);
if (ret < 0)
return ret;
This will use runtime PM to get the clocks ticking.
/* C22 read */
frame_op = FEC_MMFR_OP_READ;
frame_start = FEC_MMFR_ST;
frame_addr = regnum;
/* start a read op */
writel(frame_start | frame_op |
FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(frame_addr) |
FEC_MMFR_TA, fep->hwp + FEC_MII_DATA);
/* wait for end of transfer */
ret = fec_enet_mdio_wait(fep);
if (ret) {
netdev_err(fep->netdev, "MDIO read timeout\n");
goto out;
}
ret = FEC_MMFR_DATA(readl(fep->hwp + FEC_MII_DATA));
This all does the MDIO bus transaction
out:
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
And then tell PM that we are done. In this case, i _think_ it starts a
timer, and if there is no more MDIO activity for a while, the clocks
get disabled.
The same is done for write.
PHY polling happens once per second, using these methods, nothing
special. So the clock will get enabled on the first read, polling can
need to read a few registers, so due to the timer, the clock is left
ticking between these reads, and then after a while the clock is
disabled.
My guess is, you can have the clock disabled 80% of the time, which is
probably going to be a better way to stop the magic smoke escaping
from your hardware than slowing down the clock.
Andrew
Powered by blists - more mailing lists