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
- Lines: 223
- Date:
Thu Nov 28 15:53:14 2002
- Orig file:
linux-2.4.19/drivers/net/mii.c
- Orig date:
Fri Aug 2 17:39:44 2002
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)