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

Submitted by Hermann Lauer on Nov. 28, 2008, midnight

Details

Message ID 20081128000059.GA13712@lemon.iwr.uni-heidelberg.de
State Superseded
Delegated to: David Miller
Headers show

Commit Message

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

Comments

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 hide | download patch | download mbox

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