Patchwork sumgem problems with initializiation order at a 1000SX SERDES card [experimental patch]

login
register
mail settings
Submitter Hermann Lauer
Date Nov. 28, 2008, midnight
Message ID <20081128000059.GA13712@lemon.iwr.uni-heidelberg.de>
Download mbox | patch
Permalink /patch/11273/
State Superseded
Delegated to: David Miller
Headers show

Comments

Hermann Lauer - Nov. 28, 2008, midnight
Attached is an experimental patch which made my 1000SX sungem card (with phy_serdes) working.
As suspected, reinitialising the PCS part after the global reset in gem_reinit_chip()
gets autonegotiation working and the link is established also after an ifconfig up
command now. Access through the card did not show any errors so far.

Will try to add the missing if clauses to the patch as time allows me, comments are welcome.

Hermann
David Miller - Dec. 2, 2008, 7:35 a.m.
From: Hermann Lauer <Hermann.Lauer@iwr.uni-heidelberg.de>
Date: Fri, 28 Nov 2008 01:00:59 +0100

> Attached is an experimental patch which made my 1000SX sungem card (with phy_serdes) working.
> As suspected, reinitialising the PCS part after the global reset in gem_reinit_chip()
> gets autonegotiation working and the link is established also after an ifconfig up
> command now. Access through the card did not show any errors so far.
> 
> Will try to add the missing if clauses to the patch as time allows me, comments are welcome.

Thanks a lot for doing this work and tracking down the problem.

I'll take a look at your patch as soon as I can.

Thanks again.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch

--- linux-2.6.24-2.6.24/drivers/net/sungem.c.2627	2008-11-28 00:40:58.000000000 +0100
+++ linux-2.6.24-2.6.24/drivers/net/sungem.c	2008-11-28 00:34:46.000000000 +0100
@@ -1324,7 +1324,7 @@ 
 	    	   gp->phy_type == phy_serdes) {
 		u32 pcs_lpa = readl(gp->regs + PCS_MIILP);
 
-		if (pcs_lpa & PCS_MIIADV_FD)
+		if ((pcs_lpa & PCS_MIIADV_FD) || gp->phy_type == phy_serdes)
 			full_duplex = 1;
 		speed = SPEED_1000;
 	}
@@ -1488,6 +1488,9 @@ 
 			val = readl(gp->regs + PCS_MIISTAT);
 
 		if ((val & PCS_MIISTAT_LS) != 0) {
+		  if (gp->lstate == link_up)
+			 goto restart;
+
 			gp->lstate = link_up;
 			netif_carrier_on(gp->dev);
 			(void)gem_set_link_modes(gp);
@@ -1714,7 +1717,7 @@ 
 		/* Reset PCS unit. */
 		val = readl(gp->regs + PCS_MIICTRL);
 		val |= PCS_MIICTRL_RST;
-		writeb(val, gp->regs + PCS_MIICTRL);
+		writel(val, gp->regs + PCS_MIICTRL);
 
 		limit = 32;
 		while (readl(gp->regs + PCS_MIICTRL) & PCS_MIICTRL_RST) {
@@ -2095,12 +2098,51 @@ 
 /* Must be invoked under gp->lock and gp->tx_lock. */
 static void gem_reinit_chip(struct gem *gp)
 {
+  int val;
 	/* Reset the chip */
 	gem_reset(gp);
 
 	/* Make sure ints are disabled */
 	gem_disable_ints(gp);
 
+	/* Make sure PCS is disabled while changing advertisement
+	 * configuration.
+	 */
+	val = readl(gp->regs + PCS_CFG);
+	val &= ~(PCS_CFG_ENABLE | PCS_CFG_TO);
+	writel(val, gp->regs + PCS_CFG);
+
+	/* Advertise all capabilities except assymetric
+	 * pause.
+	 */
+	val = readl(gp->regs + PCS_MIIADV);
+	val |= (PCS_MIIADV_FD | PCS_MIIADV_HD |
+		PCS_MIIADV_SP | PCS_MIIADV_AP);
+	writel(val, gp->regs + PCS_MIIADV);
+
+	/* Enable and restart auto-negotiation, disable wrapback/loopback,
+	 * and re-enable PCS.
+	 */
+	val = readl(gp->regs + PCS_MIICTRL);
+	val |= (PCS_MIICTRL_RAN | PCS_MIICTRL_ANE);
+	val &= ~PCS_MIICTRL_WB;
+	writel(val, gp->regs + PCS_MIICTRL);
+
+	val = readl(gp->regs + PCS_CFG);
+	val |= PCS_CFG_ENABLE;
+	writel(val, gp->regs + PCS_CFG);
+
+	/* Make sure serialink loopback is off.  The meaning
+	 * of this bit is logically inverted based upon whether
+	 * you are in Serialink or SERDES mode.
+	 */
+	val = readl(gp->regs + PCS_SCTRL);
+	if (gp->phy_type == phy_serialink)
+	  val &= ~PCS_SCTRL_LOOP;
+	else
+	  val |= PCS_SCTRL_LOOP;
+	writel(val, gp->regs + PCS_SCTRL);
+
 	/* Allocate & setup ring buffers */
 	gem_init_rings(gp);