[PATCH] drivers/net/ns83820.c: add paramter to disable auto negotiation

From: Steve Briggs
Date: Thu Feb 09 2006 - 23:00:47 EST


From: Steve Briggs <zzybaloobah@xxxxxxxxx>

This patch adds a module paramter, "auto_neg" which is
by default =1. If it's set to zero, the auto negotiation
code in ns83820_init_one() is skipped and the interface is
set to 1000F. This only applies to optical transceivers.

This is to allow this driver to work with partners that
don't support auto negotiation (the DGS-3204, for example).

This is for ns83820.c ver 0.22, kernel ver 2.6.15.3

Signed-off-by: Steve Briggs <zzybaloobah@xxxxxxxxx>

---

I use the the Netgear GA621 cards (with optical Xcvrs) and
have always had problems with autonegotiation. Specifically,
if I have 2 cards connected together and the link goes down
(either one machine goes down or the fiber gets disconnected),
the link doesn't come back up until I reboot both machines.

I've also got a Dlink DGS-3204 fiber switch that doesn't
support autonegotiation, it's 1000F only. In the
autonegotiation code in the current ns83820.c, it shows
up as
tanlpar & (TANAR_FULL_DUP | TANAR_HALF_DUP) = 0
so the determination of full/half duplex in phy_intr()
falls through entirely.

I haven't done testing beyond with the Netgear GA621 cards;
on the other hand, if you do nothing, auto_neg = 1 and the
code works as before.


--- linux-2.6.15.3/drivers/net/ns83820.c.orig 2006-02-06 17:36:47.000000000 -0600
+++ linux-2.6.15.3/drivers/net/ns83820.c 2006-02-09 21:46:57.000000000 -0600
@@ -126,6 +126,7 @@
static int ihr = 2;
static int reset_phy = 0;
static int lnksts = 0; /* CFG_LNKSTS bit polarity */
+static int auto_neg = 1; /* with an optical Xcvr, set = 0 to force to 1000F */

/* Dprintk is used for more interesting debug events */
#undef Dprintk
@@ -695,6 +696,8 @@ static void fastcall phy_intr(struct net
writel(readl(dev->base + GPIOR) & ~GPIOR_GP1_OUT,
dev->base + GPIOR);
}
+ else /* partner doesn't autonegotiate, assume 1000F */
+ fullduplex=1;

speed = 4; /* 1000F */

@@ -1967,18 +1970,28 @@ static int __devinit ns83820_init_one(st
ndev->name);
writel(readl(dev->base + GPIOR) | 0x3e8, dev->base + GPIOR);

- /* setup auto negotiation feature advertisement */
- writel(readl(dev->base + TANAR)
- | TANAR_HALF_DUP | TANAR_FULL_DUP,
- dev->base + TANAR);
-
- /* start auto negotiation */
- writel(TBICR_MR_AN_ENABLE | TBICR_MR_RESTART_AN,
- dev->base + TBICR);
- writel(TBICR_MR_AN_ENABLE, dev->base + TBICR);
- dev->linkstate = LINK_AUTONEGOTIATE;
-
- dev->CFG_cache |= CFG_MODE_1000;
+ if (auto_neg == 0) { /* don't advertise it, and set 1000F */
+ writel(readl(dev->base + TANAR) & !TANAR_HALF_DUP &
+ !TANAR_FULL_DUP, dev->base + TANAR);
+ writel(readl(dev->base + TXCFG) | TXCFG_CSI | TXCFG_HBI,
+ dev->base + TXCFG);
+ writel(readl(dev->base + RXCFG) | RXCFG_RX_FD,
+ dev->base + RXCFG);
+ dev->linkstate = LINK_UP;
+ } else {
+ /* setup auto negotiation feature advertisement */
+ writel(readl(dev->base + TANAR)
+ | TANAR_HALF_DUP | TANAR_FULL_DUP,
+ dev->base + TANAR);
+
+ /* start auto negotiation */
+ writel(TBICR_MR_AN_ENABLE | TBICR_MR_RESTART_AN,
+ dev->base + TBICR);
+ writel(TBICR_MR_AN_ENABLE, dev->base + TBICR);
+ dev->linkstate = LINK_AUTONEGOTIATE;
+ }
+
+ dev->CFG_cache |= CFG_MODE_1000;
}

writel(dev->CFG_cache, dev->base + CFG);
@@ -2198,5 +2211,8 @@ MODULE_PARM_DESC(ihr, "Time in 100 us in
module_param(reset_phy, int, 0);
MODULE_PARM_DESC(reset_phy, "Set to 1 to reset the PHY on startup");

+module_param(auto_neg, int, 1);
+MODULE_PARM_DESC(auto_neg, "Set = 0 to disable auto negotiate and force 1000F (Optical only)");
+
module_init(ns83820_init);
module_exit(ns83820_exit);

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/