[epic] [PATCH] epic100-fiber support, improved

Gernot Hillier gernot@hillier.de
Mon Aug 19 10:09:23 2002


--------------Boundary-00=_3DOZ11EFAKBW9ZHPZDJ8
Content-Type: text/plain;
  charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi!

This patch allows to use the fiber interface of the SMC9432FTX NIC or oth=
er
epic-based cards using the LXT970 transceiver.

The attached patch (md5sum: abcb5c02ea3e14a6ac50badaddc465ba) applies cle=
anly=20
to 2.4.19-marcelo. If you miss the patch (i.e. if you find this message o=
n=20
some list archive stripping of attachments), you can also retrieve it fro=
m my=20
web page referenced below.

If someone needs a patch against the sources of Donald Becker, please tel=
l me=20
and I'll try to make one ASAP!

I did many final code cleanups and tried to eliminate all weaknesses you
pointed me to.

So here are the changes against the last patches I published:

* code cleanup
* no additions to check_media() running in intterrupt context any more
* replaced the long udelay in epic_open() by schedule_timeout()
* driver now checks for the right transceiver and tries to enable fiber o=
nly
  on cards having the LXT970
* module option for forcing the use of fiber interface added (options=3D6=
)
* all LXT970-specific symbols put into a new header file
  include/linux/lxt970.h - so other drivers for cards using the same
  transceiver can benefit, no changes to mii.h any more
* added some debug output for debug >=3D 2

Short overview of the functionality:

The driver reads the ID of the PHY chip. If it's a LXT970 it tries to do =
the
following steps in epic_open():

* disable auto-negotiation (not supported for fiber by LXT970)
* enable fiber interface
* wait 1.5 seconds for fiber interface to get ready
* read link status
* if we have no link, disable fiber and switch back to old code (utp/bnc)

I don't want to bore you by repeating what we've already written here, so=
 I
put up a web site containing all summed up details and some usage notes.
Please see http://www.hillier.de/linux/epic100-fiber.php3

The patch has been tested successfully with the following configurations:

SMC 9432 BTX (card with BNC and TP connector) using TP
SMC 9432 TX-MP (card with TP connector only)
SMC 9432 FTX-SC (card with fiber and TP connector): tested thoroughly sin=
ce
some weeks on 48 workstations and 2 servers running 24/7

TIA for your feedback!

This patch has also been submitted for inclusion in the 2.4.X-kernel-seri=
es to=20
linux-net.

- --
Ciao,

Gernot

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.6 (GNU/Linux)
Comment: For info see http://www.gnupg.org

iD8DBQE9XkoZk997/GGeSeIRAhzAAJ9D7sHPS3ERmya1Tnc5LTKcXmvHBgCgp8N7
/H4NZ30Gdv8v+RiDbFSpZno=3D
=3D55JX
-----END PGP SIGNATURE-----

--------------Boundary-00=_3DOZ11EFAKBW9ZHPZDJ8
Content-Type: text/x-diff;
  charset="iso-8859-1";
  name="epic100_fx_2.4.19.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="epic100_fx_2.4.19.diff"

diff -uNr linux-2.4.19.SuSE/drivers/net/epic100.c linux-2.4.19.SuSE-new/drivers/net/epic100.c
--- linux-2.4.19.SuSE/drivers/net/epic100.c	Sat Aug 17 02:32:39 2002
+++ linux-2.4.19.SuSE-new/drivers/net/epic100.c	Sat Aug 17 13:37:48 2002
@@ -63,11 +63,15 @@
 	LK1.1.13:
 	* revert version 1.1.12, power-up sequence "fix"
 
+	epic100_fx.diff:
+	* fiber link enabled on the SMC9432FTX-SC, tested during open of the interface; if no link found, utp/bnc is enabled
+	  real work done by Christoph Dolina, I made some improvements and code-cleanup (<gernot@hillier.de>) 
+	  for details see http://www.hillier.de/linux/epic100-fiber.php3
 */
 
 #define DRV_NAME	"epic100"
-#define DRV_VERSION	"1.11+LK1.1.13"
-#define DRV_RELDATE	"Mar 20, 2002"
+#define DRV_VERSION	"1.11+LK1.1.13+fx.diff"
+#define DRV_RELDATE	"Aug 9, 2002"
 
 
 /* The user-configurable values.
@@ -133,6 +137,7 @@
 #include <linux/init.h>
 #include <linux/spinlock.h>
 #include <linux/ethtool.h>
+#include <linux/lxt970.h>
 #include <linux/mii.h>
 #include <linux/crc32.h>
 #include <asm/bitops.h>
@@ -158,9 +163,9 @@
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM_DESC(debug, "EPIC/100 debug level (0-5)");
 MODULE_PARM_DESC(max_interrupt_work, "EPIC/100 maximum events handled per interrupt");
-MODULE_PARM_DESC(options, "EPIC/100: Bits 0-3: media type, bit 4: full duplex");
+MODULE_PARM_DESC(options, "EPIC/100: Bits 0-3: media type (0=auto, 1=10Base2, 6=100BaseFX), bit 4: full duplex");
 MODULE_PARM_DESC(rx_copybreak, "EPIC/100 copy breakpoint for copy-only-tiny-frames");
-MODULE_PARM_DESC(full_duplex, "EPIC/100 full duplex setting(s) (1)");
+MODULE_PARM_DESC(full_duplex, "EPIC/100 full duplex setting(s) (1=enable) - must be set manually on fiber");
 
 /*
 				Theory of Operation
@@ -345,6 +350,7 @@
 	struct mii_if_info mii;
 	unsigned int tx_full:1;				/* The Tx queue is full. */
 	unsigned int default_port:4;		/* Last dev->if_port value. */
+	unsigned int mii_phy_id:32;		/* MII_PHY_ID1 << 16 + MII_PHY_ID2  -> type of MII we have */	
 };
 
 static int epic_open(struct net_device *dev);
@@ -481,6 +487,9 @@
 	ep->chip_id = chip_idx;
 	ep->chip_flags = pci_id_tbl[chip_idx].drv_flags;
 
+	/* (Christoph Dolina): Needed for rising up the Hardware */
+	udelay(200);
+
 	/* Find the connected MII xcvrs.
 	   Doing this in open() would allow detecting external xcvrs later, but
 	   takes much time and no cards have external MII. */
@@ -502,6 +511,8 @@
 			printk(KERN_INFO DRV_NAME "(%s): Autonegotiation advertising %4.4x link "
 				   "partner %4.4x.\n",
 				   pdev->slot_name, ep->mii.advertising, mdio_read(dev, phy, 5));
+			ep->mii_phy_id = mdio_read(dev,phy,MII_PHYSID1);
+                        ep->mii_phy_id = (ep->mii_phy_id << 16) + mdio_read(dev,phy,MII_PHYSID2);
 		} else if ( ! (ep->chip_flags & NO_MII)) {
 			printk(KERN_WARNING DRV_NAME "(%s): ***WARNING***: No MII transceiver found!\n",
 			       pdev->slot_name);
@@ -661,8 +672,9 @@
 {
 	struct epic_private *ep = dev->priv;
 	long ioaddr = dev->base_addr;
-	int i;
+	int i,linkok;
 	int retval;
+        signed long remaining;
 
 	/* Soft reset the chip. */
 	outl(0x4001, ioaddr + GENCTL);
@@ -697,33 +709,84 @@
 	outl(0x0412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
 #endif
 
+	/* (Christoph Dolina): Needed for rising up the Hardware */
+	udelay(200); 
+
 	for (i = 0; i < 3; i++)
 		outl(cpu_to_le16(((u16*)dev->dev_addr)[i]), ioaddr + LAN0 + i*4);
 
 	ep->tx_threshold = TX_FIFO_THRESH;
 	outl(ep->tx_threshold, ioaddr + TxThresh);
 
-	if (media2miictl[dev->if_port & 15]) {
-		if (ep->mii_phy_cnt)
-			mdio_write(dev, ep->phys[0], MII_BMCR, media2miictl[dev->if_port&15]);
-		if (dev->if_port == 1) {
-			if (debug > 1)
-				printk(KERN_INFO "%s: Using the 10base2 transceiver, MII "
-					   "status %4.4x.\n",
-					   dev->name, mdio_read(dev, ep->phys[0], MII_BMSR));
+	udelay(200);
+
+	/* fiber media support for the SMC9432FTX-SC (using LevelOne LXT970 MII) */
+        /* if fiber was selected and we have the LXT970 MII, search for link on fiber, if not found switch to utp */ 
+	if ((dev->if_port==0 || dev->if_port==6) && ((ep->mii_phy_id & 0xfffffc00) == 0x78100000 ) ) 
+	{
+                if (debug>1)
+                        printk(KERN_INFO "%s: LXT970 found, activating fiber, waiting 1.5 sec for link up\n",dev->name);
+
+		/* disable auto-negotiation, enable full duplex and 100 Mbps (see Level One LXT970 data sheet, revision 1.1, page 11-185) */
+		mdio_write(dev, ep->phys[0], MII_BMCR, BMCR_FULLDPLX | BMCR_SPEED100);
+		/* enable fiber, Led_On must be set otherwise the fiber transceiver on the SMC9432FTX won't work ?! */
+		mdio_write(dev, ep->phys[0], MII_LXT970_CONFIG, LXT970_CONFIG_100BASEFX | LXT970_CONFIG_LEDC_ON);
+
+		/* Wait until fiber ready => so we can check for link up */
+		remaining=1.5*HZ;
+	        while (remaining)
+		{
+			set_current_state(TASK_INTERRUPTIBLE);	
+			remaining=schedule_timeout(remaining);
 		}
-	} else {
-		int mii_lpa = mdio_read(dev, ep->phys[0], MII_LPA);
-		if (mii_lpa != 0xffff) {
-			if ((mii_lpa & LPA_100FULL) || (mii_lpa & 0x01C0) == LPA_10FULL)
-				ep->mii.full_duplex = 1;
-			else if (! (mii_lpa & LPA_LPACK))
-				mdio_write(dev, ep->phys[0], MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART);
-			if (debug > 1)
-				printk(KERN_INFO "%s: Setting %s-duplex based on MII xcvr %d"
-					   " register read of %4.4x.\n", dev->name,
-					   ep->mii.full_duplex ? "full" : "half",
-					   ep->phys[0], mii_lpa);
+
+		/* Status-Reg (0x14): check for link up */
+		linkok = mdio_read(dev, ep->phys[0], MII_LXT970_CHIPSTAT);
+		if (debug>1)
+			if (linkok & LXT970_CHIPSTAT_LINKOK)
+				printk(KERN_INFO "%s: link on fiber interface detected\n", dev->name);
+			else
+				printk(KERN_INFO "%s: no link on fiber interface\n", dev->name);
+	}
+	else
+	{
+		linkok=0; /* we have no link till now */
+	}
+
+	/* IF no Link, change type of media */
+	if ( (dev->if_port != 6) && (( linkok & LXT970_CHIPSTAT_LINKOK) == 0) ) {
+		if (debug > 1)
+			printk(KERN_INFO "%s: change media to utp/bnc\n", dev->name);
+
+		/* if we have LXT970 transceiver, then disable fiber interface */
+		if ( (ep->mii_phy_id & 0xfffffc00) == 0x78100000 ) 
+			mdio_write(dev, ep->phys[0], MII_LXT970_CONFIG, 0x0000);
+		/* re-enable auto-negotiation */
+		mdio_write(dev, ep->phys[0], MII_BMCR, BMCR_ANENABLE); 
+
+		/* now let's activate utp or bnc */
+		if (media2miictl[dev->if_port & 15]) {
+			if (ep->mii_phy_cnt)
+				mdio_write(dev, ep->phys[0], MII_BMCR, media2miictl[dev->if_port&15]);
+			if (dev->if_port == 1) {
+				if (debug > 1)
+					printk(KERN_INFO "%s: Using the 10base2 transceiver, MII "
+						   "status %4.4x.\n",
+						   dev->name, mdio_read(dev, ep->phys[0], MII_BMSR));
+			}
+		} else {
+			int mii_lpa = mdio_read(dev, ep->phys[0], MII_LPA);
+			if (mii_lpa != 0xffff) {
+				if ((mii_lpa & LPA_100FULL) || (mii_lpa & 0x01C0) == LPA_10FULL)
+					ep->mii.full_duplex = 1;
+ 				else if (! (mii_lpa & LPA_LPACK))
+					mdio_write(dev, ep->phys[0], MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART);
+				if (debug > 1)
+					printk(KERN_INFO "%s: Setting %s-duplex based on MII xcvr %d"
+						   " register read of %4.4x.\n", dev->name,
+						   ep->mii.full_duplex ? "full" : "half",
+						   ep->phys[0], mii_lpa);
+			}
 		}
 	}
 
diff -uNr linux-2.4.19.SuSE/include/linux/lxt970.h linux-2.4.19.SuSE-new/include/linux/lxt970.h
--- linux-2.4.19.SuSE/include/linux/lxt970.h	Thu Jan  1 01:00:00 1970
+++ linux-2.4.19.SuSE-new/include/linux/lxt970.h	Sat Aug 17 02:10:49 2002
@@ -0,0 +1,80 @@
+/*
+ * linux/lxt970.h: definitions for Level One LXT970 MII-compatible transceivers
+ *
+ * Copyright (C) 2002 Gernot Hillier (<gernot@hillier.de>)
+ */
+
+#ifndef __LINUX_LXT970_H
+#define __LINUX_LXT970_H
+
+#include <linux/mii.h>
+
+/*
+ * These are the register definitios for the Level One LXT970 MII-transceiver. 
+ * 
+ * As Level One isn't existing any more, there doesn't seem to be an official place 
+ * for downloading data sheets out there (at least I didn't find one). 
+ *
+ * Therefore I mirrored a copy of the data sheet on http://www.hillier.de/linux/970REV11.PDF
+ *
+ * The LXT970 is capable of both 10 and 100Mbps ethernet, in both
+ * half and full duplex mode.  It supports cat5 and fiber optics.
+ *
+ */
+
+/* vendor specific register set for LXT970 */
+#define MII_LXT970_MIRROR   0x10        /* Mirror Register             */
+#define MII_LXT970_INTENAB  0x11        /* Interrupt Enable Register   */
+#define MII_LXT970_INTSTAT  0x12        /* Interrupt Status Register   */
+#define MII_LXT970_CONFIG   0x13        /* Config Register             */
+#define MII_LXT970_CHIPSTAT 0x14        /* Chip Status Register        */
+
+/* LXT970 Interrupt Enable Register. */
+#define LXT970_INTENAB_TINT     0x0001  /* force MDINT                 */
+#define LXT970_INTENAB_INTEN    0x0002  /* enable interrupts           */
+#define LXT970_INTENAB_RESV     0xfffc  /* Unused...                   */
+
+/* LXT970 Interrupt Status Register. */
+#define LXT970_INTSTAT_RESV     0x3fff  /* Unused...                   */
+#define LXT970_INTSTAT_XTALOK   0x4000  /* XTAL circuit available      */
+#define LXT970_INTSTAT_MINT     0x8000  /* MII interrupt pending       */
+
+/* LXT970 Configuration Register. */
+#define LXT970_CONFIG_TRANSDISC 0x0001  /* disconnect TP transmitter   */
+#define LXT970_CONFIG_RESV1     0x0002  /* Unused...                   */
+#define LXT970_CONFIG_100BASEFX 0x0004  /* enable fiber interface      */
+#define LXT970_CONFIG_NOSCRAM   0x0008  /* bypass scramblers           */
+#define LXT970_CONFIG_5BSYMBOL  0x0010  /* 5-bit Symbol Mode           */
+#define LXT970_CONFIG_TXCLOCK   0x0020  /* special TX clock mode       */
+#define LXT970_CONFIG_LEDC_COLL 0x0000  /* LEDC indicates collision    */
+#define LXT970_CONFIG_LEDC_OFF  0x0040  /* LEDC off                    */
+#define LXT970_CONFIG_LEDC_ACT  0x0080  /* LEDC indicates activity     */
+#define LXT970_CONFIG_LEDC_ON   0x00c0  /* LEDC continuously on        */
+#define LXT970_CONFIG_NOLINKTST 0x0100  /* disable 10BaseT link test   */
+#define LXT970_CONFIG_NOJABBER  0x0200  /* disable 10BaseT jabber      */
+#define LXT970_CONFIG_SQE       0x0400  /* enable 10BaseT SQE          */
+#define LXT970_CONFIG_NOTPLOOPB 0x0800  /* disable 10BaseT TP loopback */
+#define LXT970_CONFIG_MDIOINT   0x1000  /* enable MDIO interrupt       */
+#define LXT970_CONFIG_REPEATER  0x2000  /* enable repeater mode        */
+#define LXT970_CONFIG_TXTEST    0x4000  /* enable 100BaseT transmit tst*/
+#define LXT970_CONFIG_RESV2     0x8000  /* Unused...                   */
+
+/* LXT970 Chip Status Register. */
+#define LXT970_CHIPSTAT_NOPLL   0x0001  /* 100BaseTX/FX recv not locked*/
+#define LXT970_CHIPSTAT_RESV1   0x0002  /* Unused...                   */
+#define LXT970_CHIPSTAT_LVFAULT 0x0004  /* low voltage fault on VCC    */
+#define LXT970_CHIPSTAT_RESV2   0x0008  /* Unused...                   */
+#define LXT970_CHIPSTAT_MLT3ERR 0x0010  /* MLT3 encoding error         */
+#define LXT970_CHIPSTAT_SYMBERR 0x0020  /* Symbol Error detected       */
+#define LXT970_CHIPSTAT_STREAML 0x0040  /* scrambler/decoder locked    */
+#define LXT970_CHIPSTAT_RESV3   0x0080  /* Unused...                   */
+#define LXT970_CHIPSTAT_PAGERCV 0x0100  /* duplicate of EXPANSION_LCWP */
+#define LXT970_CHIPSTAT_ANCOMPL 0x0200  /* dupl of BMSR_ANEGCOMPLETE   */
+#define LXT970_CHIPSTAT_RESV4   0x0400  /* Unused...                   */
+#define LXT970_CHIPSTAT_100MBPS 0x0800  /* 100 Mbps operation          */
+#define LXT970_CHIPSTAT_FULLDPL 0x1000  /* full duplex operation       */
+#define LXT970_CHIPSTAT_LINKOK  0x2000  /* link is up (dynamic)        */
+#define LXT970_CHIPSTAT_RESV5   0xc000  /* Unused...                   */
+
+#endif /* __LINUX_LXT970_H */
+

--------------Boundary-00=_3DOZ11EFAKBW9ZHPZDJ8--