patch-2.4.20 linux-2.4.20/drivers/net/mii.c

Next file: linux-2.4.20/drivers/net/natsemi.c
Previous file: linux-2.4.20/drivers/net/meth.h
Back to the patch index
Back to the overall index

diff -urN linux-2.4.19/drivers/net/mii.c linux-2.4.20/drivers/net/mii.c
@@ -3,7 +3,27 @@
 	mii.c: MII interface library
 
 	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
-	Copyright 2001 Jeff Garzik
+	Copyright 2001,2002 Jeff Garzik
+
+	Various code came from myson803.c and other files by
+	Donald Becker.  Copyright:
+
+		Written 1998-2002 by Donald Becker.
+
+		This software may be used and distributed according
+		to the terms of the GNU General Public License (GPL),
+		incorporated herein by reference.  Drivers based on
+		or derived from this code fall under the GPL and must
+		retain the authorship, copyright and license notice.
+		This file is not a complete program and may only be
+		used when the entire operating system is licensed
+		under the GPL.
+
+		The author may be reached as becker@scyld.com, or C/O
+		Scyld Computing Corporation
+		410 Severn Ave., Suite 210
+		Annapolis MD 21403
+
 
  */
 
@@ -122,7 +142,7 @@
 		bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
 		mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
 
-		mii->duplex_lock = 0;
+		mii->force_media = 0;
 	} else {
 		u32 bmcr, tmp;
 
@@ -130,16 +150,16 @@
 		bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
 		tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX);
 		if (ecmd->speed == SPEED_100)
-			bmcr |= BMCR_SPEED100;
+			tmp |= BMCR_SPEED100;
 		if (ecmd->duplex == DUPLEX_FULL) {
-			bmcr |= BMCR_FULLDPLX;
+			tmp |= BMCR_FULLDPLX;
 			mii->full_duplex = 1;
 		} else
 			mii->full_duplex = 0;
 		if (bmcr != tmp)
-			mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
+			mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp);
 
-		mii->duplex_lock = 1;
+		mii->force_media = 1;
 	}
 	return 0;
 }
@@ -170,6 +190,155 @@
 	return r;
 }
 
+void mii_check_link (struct mii_if_info *mii)
+{
+	int cur_link = mii_link_ok(mii);
+	int prev_link = netif_carrier_ok(mii->dev);
+
+	if (cur_link && !prev_link)
+		netif_carrier_on(mii->dev);
+	else if (prev_link && !cur_link)
+		netif_carrier_off(mii->dev);
+}
+
+unsigned int mii_check_media (struct mii_if_info *mii,
+			      unsigned int ok_to_print,
+			      unsigned int init_media)
+{
+	unsigned int old_carrier, new_carrier;
+	int advertise, lpa, media, duplex;
+
+	/* if forced media, go no further */
+	if (mii->force_media)
+		return 0; /* duplex did not change */
+
+	/* check current and old link status */
+	old_carrier = netif_carrier_ok(mii->dev) ? 1 : 0;
+	new_carrier = (unsigned int) mii_link_ok(mii);
+
+	/* if carrier state did not change, this is a "bounce",
+	 * just exit as everything is already set correctly
+	 */
+	if ((!init_media) && (old_carrier == new_carrier))
+		return 0; /* duplex did not change */
+
+	/* no carrier, nothing much to do */
+	if (!new_carrier) {
+		netif_carrier_off(mii->dev);
+		if (ok_to_print)
+			printk(KERN_INFO "%s: link down\n", mii->dev->name);
+		return 0; /* duplex did not change */
+	}
+
+	/*
+	 * we have carrier, see who's on the other end
+	 */
+	netif_carrier_on(mii->dev);
+
+	/* get MII advertise and LPA values */
+	if ((!init_media) && (mii->advertising))
+		advertise = mii->advertising;
+	else {
+		advertise = mii->mdio_read(mii->dev, mii->phy_id, MII_ADVERTISE);
+		mii->advertising = advertise;
+	}
+	lpa = mii->mdio_read(mii->dev, mii->phy_id, MII_LPA);
+
+	/* figure out media and duplex from advertise and LPA values */
+	media = mii_nway_result(lpa & advertise);
+	duplex = (media & ADVERTISE_FULL) ? 1 : 0;
+
+	if (ok_to_print)
+		printk(KERN_INFO "%s: link up, %sMbps, %s-duplex, lpa 0x%04X\n",
+		       mii->dev->name,
+		       media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ?
+		       		"100" : "10",
+		       duplex ? "full" : "half",
+		       lpa);
+
+	if ((init_media) || (mii->full_duplex != duplex)) {
+		mii->full_duplex = duplex;
+		return 1; /* duplex changed */
+	}
+
+	return 0; /* duplex did not change */
+}
+
+int generic_mii_ioctl(struct mii_if_info *mii_if,
+		      struct mii_ioctl_data *mii_data, int cmd,
+		      unsigned int *duplex_chg_out)
+{
+	int rc = 0;
+	unsigned int duplex_changed = 0;
+
+	if (duplex_chg_out)
+		*duplex_chg_out = 0;
+
+	mii_data->phy_id &= mii_if->phy_id_mask;
+	mii_data->reg_num &= mii_if->reg_num_mask;
+
+	switch(cmd) {
+	case SIOCDEVPRIVATE:	/* binary compat, remove in 2.5 */
+	case SIOCGMIIPHY:
+		mii_data->phy_id = mii_if->phy_id;
+		/* fall through */
+
+	case SIOCDEVPRIVATE + 1:/* binary compat, remove in 2.5 */
+	case SIOCGMIIREG:
+		mii_data->val_out =
+			mii_if->mdio_read(mii_if->dev, mii_data->phy_id,
+					  mii_data->reg_num);
+		break;
+
+	case SIOCDEVPRIVATE + 2:/* binary compat, remove in 2.5 */
+	case SIOCSMIIREG: {
+		u16 val = mii_data->val_in;
+
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		if (mii_data->phy_id == mii_if->phy_id) {
+			switch(mii_data->reg_num) {
+			case MII_BMCR: {
+				unsigned int new_duplex = 0;
+				if (val & (BMCR_RESET|BMCR_ANENABLE))
+					mii_if->force_media = 0;
+				else
+					mii_if->force_media = 1;
+				if (mii_if->force_media &&
+				    (val & BMCR_FULLDPLX))
+					new_duplex = 1;
+				if (mii_if->full_duplex != new_duplex) {
+					duplex_changed = 1;
+					mii_if->full_duplex = new_duplex;
+				}
+				break;
+			}
+			case MII_ADVERTISE:
+				mii_if->advertising = val;
+				break;
+			default:
+				/* do nothing */
+				break;
+			}
+		}
+
+		mii_if->mdio_write(mii_if->dev, mii_data->phy_id,
+				   mii_data->reg_num, val);
+		break;
+	}
+
+	default:
+		rc = -EOPNOTSUPP;
+		break;
+	}
+
+	if ((rc == 0) && (duplex_chg_out) && (duplex_changed))
+		*duplex_chg_out = 1;
+
+	return rc;
+}
+
 MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>");
 MODULE_DESCRIPTION ("MII hardware support library");
 MODULE_LICENSE("GPL");
@@ -178,3 +347,7 @@
 EXPORT_SYMBOL(mii_nway_restart);
 EXPORT_SYMBOL(mii_ethtool_gset);
 EXPORT_SYMBOL(mii_ethtool_sset);
+EXPORT_SYMBOL(mii_check_link);
+EXPORT_SYMBOL(mii_check_media);
+EXPORT_SYMBOL(generic_mii_ioctl);
+

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)