netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* net/fec on i.MX28: failure after network cable unplug or device down
@ 2011-10-10 13:17 Uwe Kleine-König
  2011-10-10 13:52 ` Lothar Waßmann
  0 siblings, 1 reply; 2+ messages in thread
From: Uwe Kleine-König @ 2011-10-10 13:17 UTC (permalink / raw)
  To: netdev; +Cc: Shawn Guo, Wolfram Sang, Lothar Waßmann

Hello,

I currently see the problem on two different i.MX28 based system
(Freescale's mx28evk and a Karo TX28) that after unplugging and
reconnection of the network cable or ifconfig down; ifconfig up; the
network is dead. That means nothing is sent or received anymore.

ifconfig up dies with:

	[   32.120000] FEC: MDIO read timeout
	[   32.120000] eth0: could not attach to PHY
	ifconfig: SIOCSIFFLAGS: Connection timed out

after unplugging the network cable I get:

	[   25.520000] PHY: 1:00 - Link is Down
	[   26.530000] FEC: MDIO read timeout

In both cases the mdio read operation doesn't fire the mii irq, though
the FEC_MII_DATA contains data that looks right and the interrupt
register (FEC_IEVENT) has the mii bit set and according to the mask
register (FEC_IMASK) the irq isn't masked.

When commenting out

	writel(1, fep->hwp + FEC_ECNTRL);

(i.e. don't reset the network unit) in fec_stop it works (but Wolfram
seems to remember that doing so breaks e.g. i.MX35. We have not checked
yet).

Strange enough with the reset commented out in fec_stop, fec_restart
resets the fec (when the cable is reconnected) but without breaking it.

I tried to restore more registers in fec_stop (most notably FEC_R_CNTRL
that has some mii fields) but without success.

Do you see this problem, too? Maybe do you have an idea to fix it?
Currently I use the following patch:

diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index 5b631fe..8c1330f 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -458,6 +458,8 @@ static void
 fec_stop(struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
+	const struct platform_device_id *id_entry =
+				platform_get_device_id(fep->pdev);
 
 	/* We cannot expect a graceful transmit stop without link !!! */
 	if (fep->link) {
@@ -467,11 +469,13 @@ fec_stop(struct net_device *ndev)
 			printk("fec_stop : Graceful transmit stop did not complete !\n");
 	}
 
-	/* Whack a reset.  We should wait for this. */
-	writel(1, fep->hwp + FEC_ECNTRL);
-	udelay(10);
-	writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
-	writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
+	if (!(id_entry->driver_data & FEC_QUIRK_ENET_MAC)) {
+		/* Whack a reset.  We should wait for this. */
+		writel(1, fep->hwp + FEC_ECNTRL);
+		udelay(10);
+		writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
+		writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
+	}
 }
 
but this feels wrong because sending and receiving isn't disabled in
hardware without link then.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

* Re: net/fec on i.MX28: failure after network cable unplug or device down
  2011-10-10 13:17 net/fec on i.MX28: failure after network cable unplug or device down Uwe Kleine-König
@ 2011-10-10 13:52 ` Lothar Waßmann
  0 siblings, 0 replies; 2+ messages in thread
From: Lothar Waßmann @ 2011-10-10 13:52 UTC (permalink / raw)
  To: Uwe Kleine-König; +Cc: netdev, Shawn Guo, Wolfram Sang

[-- Attachment #1: message body and .signature --]
[-- Type: text/plain, Size: 846 bytes --]

Hi,

Uwe Kleine-König writes:
> Hello,
> 
> I currently see the problem on two different i.MX28 based system
> (Freescale's mx28evk and a Karo TX28) that after unplugging and
> reconnection of the network cable or ifconfig down; ifconfig up; the
> network is dead. That means nothing is sent or received anymore.
> 
I already solved this problem (and some others too), but wasn't able
to send any patch yet.

The FEC of the i.MX28 requires the ETHER_EN bit in the ECR to be set
for the MII interface to work. Resetting the interface upon shutdown
is required though, because otherwise the receiver will remain active
and use the stale DMA descriptors in memory to store received packets!

Furthermore the (R)MII mode must be configured correctly in the RCR
register.

The current state of my patch is appended for reference.


Lothar Waßmann
-- 

[-- Attachment #2: fec-cleanup --]
[-- Type: application/octet-stream, Size: 3610 bytes --]

Index: linux/drivers/net/fec.c
===================================================================
--- linux.orig/drivers/net/fec.c	2011-09-13 09:58:38.000000000 +0200
+++ linux/drivers/net/fec.c	2011-09-13 09:58:41.000000000 +0200
@@ -486,10 +486,16 @@
 	writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
 }
 
+/* prevent the FEC from transmitting/receiving packets, but leave
+ * the MII interface active to detect link change
+ */
 static void
 fec_stop(struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
+	const struct platform_device_id *id_entry =
+				platform_get_device_id(fep->pdev);
+	u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8);
 
 	/* We cannot expect a graceful transmit stop without link !!! */
 	if (fep->link) {
@@ -504,8 +510,33 @@
 	udelay(10);
 	writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
 	writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
+
+	if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
+		/* i.MX28 requires ETHER_EN enabled to be able to
+		 * access the PHY registers and the RMII mode properly set to
+		 * be able to detect link changes
+		 */
+		writel(2, fep->hwp + FEC_ECNTRL);
+		writel(rmii_mode, fep->hwp + FEC_R_CNTRL);
+	}
 }
 
+/* shutdown the FEC and the MII interface */
+static void
+fec_shutdown(struct net_device *ndev)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+
+	/* We cannot expect a graceful transmit stop without link !!! */
+	if (fep->link) {
+		writel(1, fep->hwp + FEC_X_CNTRL); /* Graceful transmit stop */
+		udelay(10);
+		if (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_GRA))
+			printk("fec_stop : Graceful transmit stop did not complete !\n");
+	}
+
+	writel(0, fep->hwp + FEC_ECNTRL);
+}
 
 static void
 fec_timeout(struct net_device *ndev)
@@ -789,7 +820,7 @@
 			iap = (unsigned char *)FEC_FLASHMAC;
 #else
 		if (pdata)
-			memcpy(iap, pdata->mac, ETH_ALEN);
+			iap = (unsigned char *)&pdata->mac;
 #endif
 	}
 
@@ -836,6 +867,8 @@
 	if (phy_dev->link) {
 		if (fep->full_duplex != phy_dev->duplex) {
 			fec_restart(ndev, phy_dev->duplex);
+			/* prevent unnecessary second fec_restart() below */
+			fep->link = phy_dev->link;
 			status_change = 1;
 		}
 	}
@@ -1052,8 +1085,6 @@
 
 static void fec_enet_mii_remove(struct fec_enet_private *fep)
 {
-	if (fep->phy_dev)
-		phy_disconnect(fep->phy_dev);
 	mdiobus_unregister(fep->mii_bus);
 	kfree(fep->mii_bus->irq);
 	mdiobus_free(fep->mii_bus);
@@ -1184,6 +1215,8 @@
 fec_enet_open(struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
+	const struct platform_device_id *id_entry =
+				platform_get_device_id(fep->pdev);
 	int ret;
 
 	/* I should reset the ring buffers here, but I don't yet know
@@ -1214,7 +1247,7 @@
 	/* Don't know what to do yet. */
 	fep->opened = 0;
 	netif_stop_queue(ndev);
-	fec_stop(ndev);
+	fec_shutdown(ndev);
 
 	if (fep->phy_dev) {
 		phy_stop(fep->phy_dev);
@@ -1518,7 +1551,7 @@
 		}
 	}
 
-	fep->clk = clk_get(&pdev->dev, "fec_clk");
+	fep->clk = clk_get(&pdev->dev, NULL);
 	if (IS_ERR(fep->clk)) {
 		ret = PTR_ERR(fep->clk);
 		goto failed_clk;
@@ -1570,13 +1603,18 @@
 	struct net_device *ndev = platform_get_drvdata(pdev);
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	struct resource *r;
+	int i;
 
-	fec_stop(ndev);
+	unregister_netdev(ndev);
 	fec_enet_mii_remove(fep);
+	for (i = 0; i < 3; i++) {
+		int irq = platform_get_irq(pdev, i);
+		if (irq > 0)
+			free_irq(irq, ndev);
+	}
 	clk_disable(fep->clk);
 	clk_put(fep->clk);
 	iounmap(fep->hwp);
-	unregister_netdev(ndev);
 	free_netdev(ndev);
 
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);

[-- Attachment #3: message body text --]
[-- Type: text/plain, Size: 367 bytes --]

___________________________________________________________

Ka-Ro electronics GmbH | Pascalstraße 22 | D - 52076 Aachen
Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
Geschäftsführer: Matthias Kaussen
Handelsregistereintrag: Amtsgericht Aachen, HRB 4996

www.karo-electronics.de | info@karo-electronics.de
___________________________________________________________

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

end of thread, other threads:[~2011-10-10 13:52 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-10-10 13:17 net/fec on i.MX28: failure after network cable unplug or device down Uwe Kleine-König
2011-10-10 13:52 ` Lothar Waßmann

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).