mbox series

[0/2] net: xlinx: mdio: recheck condition after timeout

Message ID 20181030093139.10226-1-kurt@linutronix.de (mailing list archive)
Headers show
Series net: xlinx: mdio: recheck condition after timeout | expand

Message

Kurt Kanzenbach Oct. 30, 2018, 9:31 a.m. UTC
Hi,

the Xilinx mdio wait functions may return false positives under certain
circumstances: If the functions get preempted between reading the corresponding
mdio register and checking for the timeout, they could falsely indicate a
timeout.

In order to avoid the issue, the condition should be rechecked in the timeout
case.

Kurt Kanzenbach (2):
  net: axienet: recheck condition after timeout in mdio_wait()
  net: xilinx_emaclite: recheck condition after timeout in mdio_wait()

 drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c | 21 ++++++++++++++++-----
 drivers/net/ethernet/xilinx/xilinx_emaclite.c     | 20 +++++++++++++++-----
 2 files changed, 31 insertions(+), 10 deletions(-)

Comments

Andrew Lunn Oct. 30, 2018, 12:08 p.m. UTC | #1
On Tue, Oct 30, 2018 at 10:31:37AM +0100, Kurt Kanzenbach wrote:
> Hi,
> 
> the Xilinx mdio wait functions may return false positives under certain
> circumstances: If the functions get preempted between reading the corresponding
> mdio register and checking for the timeout, they could falsely indicate a
> timeout.

Hi Kurt

I wonder if it would be possible to add a readx_poll_timeout() which
passes two parameters to op()?

I keep seeing this basic problem in various drivers, and try to point
people towards readx_poll_timeout(), but it is not the best of fit.

Otherwise, could you add a axienet_ior_read_mcr(lp), and use
readx_poll_timeout() as is?

       Andrew
Andrew Lunn Oct. 30, 2018, 12:10 p.m. UTC | #2
On Tue, Oct 30, 2018 at 10:31:39AM +0100, Kurt Kanzenbach wrote:
> The function could report a false positive if it gets preempted between reading
> the XEL_MDIOCTRL_OFFSET register and checking for the timeout.  In such a case,
> the condition has to be rechecked to avoid false positives.
> 
> Therefore, check for expected condition even after the timeout occurred.
> 
> Signed-off-by: Kurt Kanzenbach <kurt@linutronix.de>
> ---
>  drivers/net/ethernet/xilinx/xilinx_emaclite.c | 20 +++++++++++++++-----
>  1 file changed, 15 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/net/ethernet/xilinx/xilinx_emaclite.c b/drivers/net/ethernet/xilinx/xilinx_emaclite.c
> index 639e3e99af46..957d03085bd0 100644
> --- a/drivers/net/ethernet/xilinx/xilinx_emaclite.c
> +++ b/drivers/net/ethernet/xilinx/xilinx_emaclite.c
> @@ -714,19 +714,29 @@ static irqreturn_t xemaclite_interrupt(int irq, void *dev_id)
>  static int xemaclite_mdio_wait(struct net_local *lp)
>  {
>  	unsigned long end = jiffies + 2;
> +	u32 val;
>  
>  	/* wait for the MDIO interface to not be busy or timeout
>  	 * after some time.
>  	 */
> -	while (xemaclite_readl(lp->base_addr + XEL_MDIOCTRL_OFFSET) &
> -			XEL_MDIOCTRL_MDIOSTS_MASK) {
> +	while (1) {
> +		val = xemaclite_readl(lp->base_addr + XEL_MDIOCTRL_OFFSET);

Hi Kurt

It looks like readx_poll_timeout() should work here.

   Andrew
Radhey Shyam Pandey Oct. 30, 2018, 12:58 p.m. UTC | #3
<snip>
> 
> On Tue, Oct 30, 2018 at 10:31:39AM +0100, Kurt Kanzenbach wrote:
> > The function could report a false positive if it gets preempted between
> reading
> > the XEL_MDIOCTRL_OFFSET register and checking for the timeout.  In such a
> case,
> > the condition has to be rechecked to avoid false positives.
> >
> > Therefore, check for expected condition even after the timeout occurred.
> >
> > Signed-off-by: Kurt Kanzenbach <kurt@linutronix.de>
> > ---
> >  drivers/net/ethernet/xilinx/xilinx_emaclite.c | 20 +++++++++++++++-----
> >  1 file changed, 15 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/net/ethernet/xilinx/xilinx_emaclite.c
> b/drivers/net/ethernet/xilinx/xilinx_emaclite.c
> > index 639e3e99af46..957d03085bd0 100644
> > --- a/drivers/net/ethernet/xilinx/xilinx_emaclite.c
> > +++ b/drivers/net/ethernet/xilinx/xilinx_emaclite.c
> > @@ -714,19 +714,29 @@ static irqreturn_t xemaclite_interrupt(int irq, void
> *dev_id)
> >  static int xemaclite_mdio_wait(struct net_local *lp)
> >  {
> >  	unsigned long end = jiffies + 2;
> > +	u32 val;
> >
> >  	/* wait for the MDIO interface to not be busy or timeout
> >  	 * after some time.
> >  	 */
> > -	while (xemaclite_readl(lp->base_addr + XEL_MDIOCTRL_OFFSET) &
> > -			XEL_MDIOCTRL_MDIOSTS_MASK) {
> > +	while (1) {
> > +		val = xemaclite_readl(lp->base_addr +
> XEL_MDIOCTRL_OFFSET);
> 
> Hi Kurt
> 
> It looks like readx_poll_timeout() should work here.

Yes, valid point. readx_poll_timeout API repoll addr after timeout.
Reusing it would simplify the flow.

> 
>    Andrew
Kurt Kanzenbach Oct. 30, 2018, 1:47 p.m. UTC | #4
Hi Andrew,

On Tue, Oct 30, 2018 at 01:08:31PM +0100, Andrew Lunn wrote:
> On Tue, Oct 30, 2018 at 10:31:37AM +0100, Kurt Kanzenbach wrote:
> > Hi,
> >
> > the Xilinx mdio wait functions may return false positives under certain
> > circumstances: If the functions get preempted between reading the corresponding
> > mdio register and checking for the timeout, they could falsely indicate a
> > timeout.
>
> Hi Kurt
>
> I wonder if it would be possible to add a readx_poll_timeout() which
> passes two parameters to op()?

actually I was thinking about using readx_poll_timeout(). But as you
already pointed out, it expects only one parameter for op(). I'm not
sure about adding a new readx_poll_timeout() macro.

>
> I keep seeing this basic problem in various drivers, and try to point
> people towards readx_poll_timeout(), but it is not the best of fit.
>
> Otherwise, could you add a axienet_ior_read_mcr(lp), and use
> readx_poll_timeout() as is?

I guess that would work.

I'll use readx_poll_timeout() for both wait functions and send a v2.

Thanks,
Kurt