Re: [PATCH] drivers/net/ns83820.c: add paramter to disable autonegotiation

From: Dan Faerch
Date: Fri Feb 10 2006 - 04:48:59 EST


On Thu, 2006-02-09 at 20:17 -0800, Andrew Morton wrote:
> Steve Briggs <s-briggs@xxxxxxxxxxxxxx> wrote:
> >
> > 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.
>
> Better to do this via `ethtool autoneg off'.

Actually I did somewhat the same patch about a year ago and got the same
response:

"This functionality should likelz be done via ethtool..." - Benjamin
LaHaise[1]

So i went back and spend about a week redoing the whole thing to enable
ethtool support and reposted a patch[2], but didnt receive any response
to this whatsoever. I even wrote the maintainer later on personally to
ask if something was wrong with the patch, bad coding, anything, since
there was no reply or reaction. I never received a reply.

So. There IS an ethtool patch and it works for me, though i dont know
how well its made (there must be SOME reason i didnt get a response :)).
It supports autoneg, duplex and speed if i recall correctly.
If you try it out, id love to hear comments (since this was/is the first
time i messed around in kernel stuff).


[1] http://www.kvack.org/~ftp/archives/linux-ns83820/linux-ns83820.0503
search for "Subject: Autoneg patch"

[2] http://www.kvack.org/~ftp/archives/linux-ns83820/linux-ns83820.0504
search for "Subject: Re: Autoneg patch"

- Dan Faerch

----------------------------------------------------

diff -Nru ../linux-2.6.11.4/drivers/net/ns83820.c drivers/net/ns83820.c
--- ../linux-2.6.11.4/drivers/net/ns83820.c Tue Mar 29 13:46:10 2005
+++ drivers/net/ns83820.c Tue Apr 19 11:47:34 2005
@@ -1,4 +1,4 @@
-#define _VERSION "0.20"
+#define _VERSION "0.22"
/* ns83820.c by Benjamin LaHaise with contributions.
*
* Questions/comments/discussion to linux-ns83820@xxxxxxxxxx
@@ -66,6 +66,9 @@
*
* 20040828 0.21 - add hardware vlan accleration
* by Neil Horman <nhorman@xxxxxxxxxx>
+ * 20050321 0.22 - Ethtool cmd support functions.
+ * - set autoneg&duplex via ethtool
+ * by Dan Faerch <dan@xxxxxxxxx>
* Driver Overview
* ===============
*
@@ -124,6 +127,7 @@
static int ihr = 2;
static int reset_phy = 0;
static int lnksts = 0; /* CFG_LNKSTS bit polarity */
+static int disable_autoneg = 0;

/* Dprintk is used for more interesting debug events */
#undef Dprintk
@@ -1273,6 +1277,177 @@
return &dev->stats;
}

+/* Dan Faerch: ethtool get/set support.
+ * This isnt perfect, but it does the job for me. I only own fiber, so copper support is "less-than-not-perfect".
+ * ive NEVER worked with drivers or hardware before (or programmed c for that matter), so please feel free to double check anything!!
+*/
+
+/* Let ethtool retrieve info */
+static int ns83820_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
+{ struct ns83820 *dev = PRIV(ndev);
+ u32 cfg,tanar, tbicr;
+ int have_optical = 0;
+ int fullduplex = 0;
+/*
+ Heres what other drivers show:
+ cmd->advertising =
+ cmd->speed =
+ cmd->duplex =
+ cmd->port = 0;
+ cmd->phy_address =
+ cmd->transceiver = 0;
+ cmd->autoneg =
+ cmd->maxtxpkt = 0;
+ cmd->maxrxpkt = 0;
+
+ Feel free to implement any of theese that are missing.
+*/
+
+ /*read current configuration*/
+ cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY;
+ tanar = readl(dev->base + TANAR);
+ tbicr = readl(dev->base + TBICR);
+
+ /*we have optical thingie-majiggy*/
+ if (dev->CFG_cache & CFG_TBI_EN) {
+ have_optical = 1;
+ //fullduplex = (tanar & TANAR_FULL_DUP);
+ fullduplex = (cfg & CFG_DUPSTS) ? 1 : 0;
+
+
+ } else { /*We have a copper wire (or a couple of copperwires at least.... hopefully)*/
+ fullduplex = (cfg & CFG_DUPSTS) ? 1 : 0;
+ }
+
+
+ printk(KERN_INFO "%s: T:%d-%d-%d - \n",
+ ndev->name,
+ (tanar & TANAR_FULL_DUP),
+ (cfg & CFG_DUPSTS),
+ tanar
+ );
+
+
+
+ cmd->supported = (SUPPORTED_Autoneg);
+
+ /*we have optical thingie-majiggy*/
+ if (dev->CFG_cache & CFG_TBI_EN) {
+ cmd->supported |= (SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full);
+ cmd->supported |= SUPPORTED_FIBRE;
+ cmd->port = PORT_FIBRE;
+ } /*TODO: else show copper related thingies*/
+
+ cmd->duplex = ((fullduplex) ? DUPLEX_FULL : DUPLEX_HALF);
+ cmd->speed = (
+ ((cfg / CFG_SPDSTS0) & 3) >= 2 ? SPEED_1000 :
+ (((cfg / CFG_SPDSTS0) & 3) == 1 ? SPEED_100 : SPEED_10 )
+ );
+ //cmd->autoneg = !disable_autoneg;
+ cmd->autoneg = (tbicr & TBICR_MR_AN_ENABLE) ? 1: 0;
+
+ return 0;
+}
+
+/* Let ethool change settings*/
+static int ns83820_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
+{ struct ns83820 *dev = PRIV(ndev);
+ u32 cfg,tanar;
+ int have_optical = 0;
+ int fullduplex = 0;
+
+ /*read current configuration*/
+ cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY;
+ tanar = readl(dev->base + TANAR);
+
+ /*we have optical*/
+ if (dev->CFG_cache & CFG_TBI_EN) {
+ have_optical = 1;
+ fullduplex = (tanar & TANAR_FULL_DUP);
+ // fullduplex = (cfg & CFG_DUPSTS);
+
+ } else { /*We have a copper*/
+ fullduplex = (cfg & CFG_DUPSTS);
+ }
+
+ spin_lock_irq(&dev->misc_lock);
+ spin_lock(&dev->tx_lock);
+
+ //Set Duplex
+ if ( cmd->duplex != fullduplex) { //If ethtool-setting is different than current setting
+ /*we have optical*/
+ if (have_optical) {
+ /*set full duplex*/
+ if (cmd->duplex==DUPLEX_FULL) {
+ ndev->name,
+ RXCFG,
+ RXCFG | RXCFG_RX_FD,
+ DUPLEX_FULL,
+ readl(dev->base + RXCFG),
+ readl(dev->base + RXCFG) | RXCFG_RX_FD,
+ readl(dev->base + RXCFG) | ~RXCFG_RX_FD
+
+ );
+ /* force full duplex */
+ writel(readl(dev->base + TXCFG)
+ | TXCFG_CSI | TXCFG_HBI | TXCFG_ATP,
+ dev->base + TXCFG);
+ writel(readl(dev->base + RXCFG) | RXCFG_RX_FD,
+ dev->base + RXCFG);
+ /* Light up full duplex LED */
+ writel(readl(dev->base + GPIOR) | GPIOR_GP1_OUT,
+ dev->base + GPIOR);
+ //writel(readl(dev->base + TANAR) | TANAR_FULL_DUP, dev->base + TANAR);
+ } else {
+
+
+ }
+
+ } else {
+ /*we have copper*/
+
+ }
+ printk(KERN_INFO "%s: Duplex set via ethtool\n",
+ ndev->name);
+ }
+
+ //Set Autoneg
+ if (cmd->autoneg != ((disable_autoneg) ? AUTONEG_DISABLE : AUTONEG_ENABLE )) { //If ethtool-setting is different than current setting
+ if (cmd->autoneg == AUTONEG_ENABLE) {
+ disable_autoneg=0;
+
+ /* restart 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;
+
+ printk(KERN_INFO "%s: autoneg enabled via ethtool\n",
+ ndev->name);
+ } else {
+ disable_autoneg=1;
+
+ /* disable auto negotiation */
+ writel(0x00000000,
+ dev->base + TBICR);
+ //dev->linkstate = LINK_UP;
+ }
+ printk(KERN_INFO "%s: autoneg %s via ethtool\n",
+ ndev->name,
+ (cmd->autoneg) ? "ENABLED" : "DISABLED"
+ );
+ }
+
+ phy_intr(ndev);
+
+ spin_unlock(&dev->tx_lock);
+ spin_unlock_irq(&dev->misc_lock);
+
+ return 0;
+}
+/* end ethtool get/set support -df */
+
static void ns83820_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info)
{
struct ns83820 *dev = PRIV(ndev);
@@ -1289,8 +1464,10 @@
}

static struct ethtool_ops ops = {
- .get_drvinfo = ns83820_get_drvinfo,
- .get_link = ns83820_get_link
+ .get_settings = ns83820_get_settings,
+ .set_settings = ns83820_set_settings,
+ .get_drvinfo = ns83820_get_drvinfo,
+ .get_link = ns83820_get_link
};

static void ns83820_mib_isr(struct ns83820 *dev)
@@ -1983,23 +2160,28 @@

/* setup optical transceiver if we have one */
if (dev->CFG_cache & CFG_TBI_EN) {
- printk(KERN_INFO "%s: enabling optical transceiver\n",
+ printk(KERqN_INFO "%s: enabling optical transceiver\n",
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,
- | TANAR_FULL_DUP,
+ 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;
- */
+ /* Dan Faerch : Allow disabling of autonegotiation on module param*/
+ if (!disable_autoneg) {
+ /* 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;
+ }
+ else
+ printk(KERN_INFO "%s: Skipping autonegotiation\n",
+ ndev->name);
+
+
dev->CFG_cache |= CFG_MODE_1000;
}

@@ -2220,6 +2402,9 @@

module_param(reset_phy, int, 0);
MODULE_PARM_DESC(reset_phy, "Set to 1 to reset the PHY on startup");
+
+module_param(disable_autoneg, int, 0);
+MODULE_PARM_DESC(autoneg, "Set to 1 to disable autoneg");

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/