netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH net-next v5] net: ethernet: fec: Replace interrupt driven MDIO with polled IO
@ 2020-05-02 15:25 Andrew Lunn
  2020-05-02 23:42 ` David Miller
  2020-08-15 16:55 ` Clemens Gruber
  0 siblings, 2 replies; 6+ messages in thread
From: Andrew Lunn @ 2020-05-02 15:25 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, fugang.duan, Chris Healy, Andrew Lunn

Measurements of the MDIO bus have shown that driving the MDIO bus
using interrupts is slow. Back to back MDIO transactions take about
90us, with 25us spent performing the transaction, and the remainder of
the time the bus is idle.

Replacing the completion interrupt with polled IO results in back to
back transactions of 40us. The polling loop waiting for the hardware
to complete the transaction takes around 28us. Which suggests
interrupt handling has an overhead of 50us, and polled IO nearly
halves this overhead, and doubles the MDIO performance.

Care has to be taken when setting the MII_SPEED register, or it can
trigger an MII event> That then upsets the polling, due to an
unexpected pending event.

Suggested-by: Chris Heally <cphealy@gmail.com>
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 drivers/net/ethernet/freescale/fec.h      |  4 +-
 drivers/net/ethernet/freescale/fec_main.c | 77 +++++++++++++----------
 2 files changed, 45 insertions(+), 36 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index e74dd1f86bba..a6cdd5b61921 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -376,8 +376,7 @@ struct bufdesc_ex {
 #define FEC_ENET_TS_AVAIL       ((uint)0x00010000)
 #define FEC_ENET_TS_TIMER       ((uint)0x00008000)
 
-#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII)
-#define FEC_NAPI_IMASK	FEC_ENET_MII
+#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF)
 #define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))
 
 /* ENET interrupt coalescing macro define */
@@ -543,7 +542,6 @@ struct fec_enet_private {
 	int	link;
 	int	full_duplex;
 	int	speed;
-	struct	completion mdio_done;
 	int	irq[FEC_IRQ_NUM];
 	bool	bufdesc_ex;
 	int	pause_flag;
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index c7b84bb22f75..2e209142f2d1 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -976,8 +976,8 @@ fec_restart(struct net_device *ndev)
 	writel((__force u32)cpu_to_be32(temp_mac[1]),
 	       fep->hwp + FEC_ADDR_HIGH);
 
-	/* Clear any outstanding interrupt. */
-	writel(0xffffffff, fep->hwp + FEC_IEVENT);
+	/* Clear any outstanding interrupt, except MDIO. */
+	writel((0xffffffff & ~FEC_ENET_MII), fep->hwp + FEC_IEVENT);
 
 	fec_enet_bd_init(ndev);
 
@@ -1123,7 +1123,7 @@ fec_restart(struct net_device *ndev)
 	if (fep->link)
 		writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
 	else
-		writel(FEC_ENET_MII, fep->hwp + FEC_IMASK);
+		writel(0, fep->hwp + FEC_IMASK);
 
 	/* Init the interrupt coalescing */
 	fec_enet_itr_coal_init(ndev);
@@ -1652,6 +1652,10 @@ fec_enet_interrupt(int irq, void *dev_id)
 	irqreturn_t ret = IRQ_NONE;
 
 	int_events = readl(fep->hwp + FEC_IEVENT);
+
+	/* Don't clear MDIO events, we poll for those */
+	int_events &= ~FEC_ENET_MII;
+
 	writel(int_events, fep->hwp + FEC_IEVENT);
 	fec_enet_collect_events(fep, int_events);
 
@@ -1659,16 +1663,12 @@ fec_enet_interrupt(int irq, void *dev_id)
 		ret = IRQ_HANDLED;
 
 		if (napi_schedule_prep(&fep->napi)) {
-			/* Disable the NAPI interrupts */
-			writel(FEC_NAPI_IMASK, fep->hwp + FEC_IMASK);
+			/* Disable interrupts */
+			writel(0, fep->hwp + FEC_IMASK);
 			__napi_schedule(&fep->napi);
 		}
 	}
 
-	if (int_events & FEC_ENET_MII) {
-		ret = IRQ_HANDLED;
-		complete(&fep->mdio_done);
-	}
 	return ret;
 }
 
@@ -1818,11 +1818,24 @@ static void fec_enet_adjust_link(struct net_device *ndev)
 		phy_print_status(phy_dev);
 }
 
+static int fec_enet_mdio_wait(struct fec_enet_private *fep)
+{
+	uint ievent;
+	int ret;
+
+	ret = readl_poll_timeout_atomic(fep->hwp + FEC_IEVENT, ievent,
+					ievent & FEC_ENET_MII, 2, 30000);
+
+	if (!ret)
+		writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);
+
+	return ret;
+}
+
 static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
 {
 	struct fec_enet_private *fep = bus->priv;
 	struct device *dev = &fep->pdev->dev;
-	unsigned long time_left;
 	int ret = 0, frame_start, frame_addr, frame_op;
 	bool is_c45 = !!(regnum & MII_ADDR_C45);
 
@@ -1830,8 +1843,6 @@ static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
 	if (ret < 0)
 		return ret;
 
-	reinit_completion(&fep->mdio_done);
-
 	if (is_c45) {
 		frame_start = FEC_MMFR_ST_C45;
 
@@ -1843,11 +1854,9 @@ static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
 		       fep->hwp + FEC_MII_DATA);
 
 		/* wait for end of transfer */
-		time_left = wait_for_completion_timeout(&fep->mdio_done,
-				usecs_to_jiffies(FEC_MII_TIMEOUT));
-		if (time_left == 0) {
+		ret = fec_enet_mdio_wait(fep);
+		if (ret) {
 			netdev_err(fep->netdev, "MDIO address write timeout\n");
-			ret = -ETIMEDOUT;
 			goto out;
 		}
 
@@ -1866,11 +1875,9 @@ static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
 		FEC_MMFR_TA, fep->hwp + FEC_MII_DATA);
 
 	/* wait for end of transfer */
-	time_left = wait_for_completion_timeout(&fep->mdio_done,
-			usecs_to_jiffies(FEC_MII_TIMEOUT));
-	if (time_left == 0) {
+	ret = fec_enet_mdio_wait(fep);
+	if (ret) {
 		netdev_err(fep->netdev, "MDIO read timeout\n");
-		ret = -ETIMEDOUT;
 		goto out;
 	}
 
@@ -1888,7 +1895,6 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
 {
 	struct fec_enet_private *fep = bus->priv;
 	struct device *dev = &fep->pdev->dev;
-	unsigned long time_left;
 	int ret, frame_start, frame_addr;
 	bool is_c45 = !!(regnum & MII_ADDR_C45);
 
@@ -1898,8 +1904,6 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
 	else
 		ret = 0;
 
-	reinit_completion(&fep->mdio_done);
-
 	if (is_c45) {
 		frame_start = FEC_MMFR_ST_C45;
 
@@ -1911,11 +1915,9 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
 		       fep->hwp + FEC_MII_DATA);
 
 		/* wait for end of transfer */
-		time_left = wait_for_completion_timeout(&fep->mdio_done,
-			usecs_to_jiffies(FEC_MII_TIMEOUT));
-		if (time_left == 0) {
+		ret = fec_enet_mdio_wait(fep);
+		if (ret) {
 			netdev_err(fep->netdev, "MDIO address write timeout\n");
-			ret = -ETIMEDOUT;
 			goto out;
 		}
 	} else {
@@ -1931,12 +1933,9 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
 		fep->hwp + FEC_MII_DATA);
 
 	/* wait for end of transfer */
-	time_left = wait_for_completion_timeout(&fep->mdio_done,
-			usecs_to_jiffies(FEC_MII_TIMEOUT));
-	if (time_left == 0) {
+	ret = fec_enet_mdio_wait(fep);
+	if (ret)
 		netdev_err(fep->netdev, "MDIO write timeout\n");
-		ret  = -ETIMEDOUT;
-	}
 
 out:
 	pm_runtime_mark_last_busy(dev);
@@ -2143,8 +2142,21 @@ static int fec_enet_mii_init(struct platform_device *pdev)
 	if (suppress_preamble)
 		fep->phy_speed |= BIT(7);
 
+	/* Clear MMFR to avoid to generate MII event by writing MSCR.
+	 * MII event generation condition:
+	 * - writing MSCR:
+	 *	- mmfr[31:0]_not_zero & mscr[7:0]_is_zero &
+	 *	  mscr_reg_data_in[7:0] != 0
+	 * - writing MMFR:
+	 *	- mscr[7:0]_not_zero
+	 */
+	writel(0, fep->hwp + FEC_MII_DATA);
+
 	writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
 
+	/* Clear any pending transaction complete indication */
+	writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);
+
 	fep->mii_bus = mdiobus_alloc();
 	if (fep->mii_bus == NULL) {
 		err = -ENOMEM;
@@ -3686,7 +3698,6 @@ fec_probe(struct platform_device *pdev)
 		fep->irq[i] = irq;
 	}
 
-	init_completion(&fep->mdio_done);
 	ret = fec_enet_mii_init(pdev);
 	if (ret)
 		goto failed_mii_init;
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH net-next v5] net: ethernet: fec: Replace interrupt driven MDIO with polled IO
  2020-05-02 15:25 [PATCH net-next v5] net: ethernet: fec: Replace interrupt driven MDIO with polled IO Andrew Lunn
@ 2020-05-02 23:42 ` David Miller
  2020-08-15 16:55 ` Clemens Gruber
  1 sibling, 0 replies; 6+ messages in thread
From: David Miller @ 2020-05-02 23:42 UTC (permalink / raw)
  To: andrew; +Cc: netdev, fugang.duan, cphealy

From: Andrew Lunn <andrew@lunn.ch>
Date: Sat,  2 May 2020 17:25:04 +0200

> Measurements of the MDIO bus have shown that driving the MDIO bus
> using interrupts is slow. Back to back MDIO transactions take about
> 90us, with 25us spent performing the transaction, and the remainder of
> the time the bus is idle.
> 
> Replacing the completion interrupt with polled IO results in back to
> back transactions of 40us. The polling loop waiting for the hardware
> to complete the transaction takes around 28us. Which suggests
> interrupt handling has an overhead of 50us, and polled IO nearly
> halves this overhead, and doubles the MDIO performance.
> 
> Care has to be taken when setting the MII_SPEED register, or it can
> trigger an MII event> That then upsets the polling, due to an
> unexpected pending event.
> 
> Suggested-by: Chris Heally <cphealy@gmail.com>
> Signed-off-by: Andrew Lunn <andrew@lunn.ch>
> Signed-off-by: David S. Miller <davem@davemloft.net>

Applied, thanks Andrew.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH net-next v5] net: ethernet: fec: Replace interrupt driven MDIO with polled IO
  2020-05-02 15:25 [PATCH net-next v5] net: ethernet: fec: Replace interrupt driven MDIO with polled IO Andrew Lunn
  2020-05-02 23:42 ` David Miller
@ 2020-08-15 16:55 ` Clemens Gruber
  2020-08-15 17:53   ` Andrew Lunn
  1 sibling, 1 reply; 6+ messages in thread
From: Clemens Gruber @ 2020-08-15 16:55 UTC (permalink / raw)
  To: andrew; +Cc: netdev, fugang.duan, Chris Healy, David Miller, Dave Karr

Hi,

this patch / commit f166f890c8 ("net: ethernet: fec: Replace interrupt
driven MDIO with polled IO") broke networking on i.MX6Q boards with
Marvell 88E1510 PHYs (Copper / 1000Base-T).

Reverting said commit fixes the problem.

We also reverted 7cdaa4cc4b ("net: ethernet: fec: prevent tx starvation
under high rx load") but that was just for the revert of the problematic
commit to apply cleanly on top of 5.8 / 5.8.1.

Best regards,
Clemens

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH net-next v5] net: ethernet: fec: Replace interrupt driven MDIO with polled IO
  2020-08-15 16:55 ` Clemens Gruber
@ 2020-08-15 17:53   ` Andrew Lunn
  2020-08-15 20:53     ` Clemens Gruber
  0 siblings, 1 reply; 6+ messages in thread
From: Andrew Lunn @ 2020-08-15 17:53 UTC (permalink / raw)
  To: Clemens Gruber; +Cc: netdev, fugang.duan, Chris Healy, David Miller, Dave Karr

On Sat, Aug 15, 2020 at 06:55:56PM +0200, Clemens Gruber wrote:
> Hi,
> 
> this patch / commit f166f890c8 ("net: ethernet: fec: Replace interrupt
> driven MDIO with polled IO") broke networking on i.MX6Q boards with
> Marvell 88E1510 PHYs (Copper / 1000Base-T).

Hi Clemens

Please could you try:

https://www.spinics.net/lists/netdev/msg675568.html

	Andrew

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH net-next v5] net: ethernet: fec: Replace interrupt driven MDIO with polled IO
  2020-08-15 17:53   ` Andrew Lunn
@ 2020-08-15 20:53     ` Clemens Gruber
  2020-08-15 22:50       ` Andrew Lunn
  0 siblings, 1 reply; 6+ messages in thread
From: Clemens Gruber @ 2020-08-15 20:53 UTC (permalink / raw)
  To: Andrew Lunn; +Cc: netdev, fugang.duan, Chris Healy, David Miller, Dave Karr

Hi Andrew,

On Sat, Aug 15, 2020 at 07:53:49PM +0200, Andrew Lunn wrote:
> On Sat, Aug 15, 2020 at 06:55:56PM +0200, Clemens Gruber wrote:
> > Hi,
> > 
> > this patch / commit f166f890c8 ("net: ethernet: fec: Replace interrupt
> > driven MDIO with polled IO") broke networking on i.MX6Q boards with
> > Marvell 88E1510 PHYs (Copper / 1000Base-T).
> 
> Hi Clemens
> 
> Please could you try:
> 
> https://www.spinics.net/lists/netdev/msg675568.html
> 
> 	Andrew

Thanks, this fixes it! I'll send a Tested-by in reply to the patch.

Clemens

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH net-next v5] net: ethernet: fec: Replace interrupt driven MDIO with polled IO
  2020-08-15 20:53     ` Clemens Gruber
@ 2020-08-15 22:50       ` Andrew Lunn
  0 siblings, 0 replies; 6+ messages in thread
From: Andrew Lunn @ 2020-08-15 22:50 UTC (permalink / raw)
  To: Clemens Gruber; +Cc: netdev, fugang.duan, Chris Healy, David Miller, Dave Karr

On Sat, Aug 15, 2020 at 10:53:40PM +0200, Clemens Gruber wrote:
> Hi Andrew,
> 
> On Sat, Aug 15, 2020 at 07:53:49PM +0200, Andrew Lunn wrote:
> > On Sat, Aug 15, 2020 at 06:55:56PM +0200, Clemens Gruber wrote:
> > > Hi,
> > > 
> > > this patch / commit f166f890c8 ("net: ethernet: fec: Replace interrupt
> > > driven MDIO with polled IO") broke networking on i.MX6Q boards with
> > > Marvell 88E1510 PHYs (Copper / 1000Base-T).
> > 
> > Hi Clemens
> > 
> > Please could you try:
> > 
> > https://www.spinics.net/lists/netdev/msg675568.html
> > 
> > 	Andrew
> 
> Thanks, this fixes it! I'll send a Tested-by in reply to the patch.

Thanks.

I think the final version will have one more change, as suggeted by
Fugang Duan.

       Andrew

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2020-08-15 22:50 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-05-02 15:25 [PATCH net-next v5] net: ethernet: fec: Replace interrupt driven MDIO with polled IO Andrew Lunn
2020-05-02 23:42 ` David Miller
2020-08-15 16:55 ` Clemens Gruber
2020-08-15 17:53   ` Andrew Lunn
2020-08-15 20:53     ` Clemens Gruber
2020-08-15 22:50       ` Andrew Lunn

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).