From: Jeff Garzik <jgarzik@mandrakesoft.com>
To: Linux Kernel Mailing List <linux-kernel@vger.kernel.org>,
netdev@oss.sgi.com
Cc: "David S. Miller" <davem@redhat.com>
Subject: PATCH: ethtool MII helpers
Date: Sun, 10 Jun 2001 13:34:59 -0400 [thread overview]
Message-ID: <3B23AFC3.71CE2FD2@mandrakesoft.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 476 bytes --]
Initial draft of a helper which uses generic elements present in several
net drivers to implement ethtool ioctl support in a minimum amount of
code.
I have included a sample implementation in the epic100 driver, to
illustrate how these helpers may be used. This should make it easier to
implement support across 10/100 hardware which uses primarily an MII
phy.
Comments appreciated.
--
Jeff Garzik | Andre the Giant has a posse.
Building 1024 |
MandrakeSoft |
[-- Attachment #2: mii.patch --]
[-- Type: text/plain, Size: 12420 bytes --]
Index: linux_2_4/include/linux/ethtool.h
diff -u linux_2_4/include/linux/ethtool.h:1.1.1.4 linux_2_4/include/linux/ethtool.h:1.1.1.4.84.1
--- linux_2_4/include/linux/ethtool.h:1.1.1.4 Thu Apr 19 17:55:36 2001
+++ linux_2_4/include/linux/ethtool.h Fri Jun 8 21:16:58 2001
@@ -1,4 +1,4 @@
-/* $Id: ethtool.h,v 1.1.1.4 2001/04/20 00:55:36 jgarzik Exp $
+/* $Id: ethtool.h,v 1.1.1.4.84.1 2001/06/09 04:16:58 jgarzik Exp $
* ethtool.h: Defines for Linux ethtool.
*
* Copyright (C) 1998 David S. Miller (davem@redhat.com)
@@ -34,13 +34,15 @@
char bus_info[32]; /* Bus info for this interface. For PCI
* devices, use pci_dev->slot_name. */
char reserved1[32];
- char reserved2[32];
+ char reserved2[28];
+ u32 regdump_len; /* Amount of data from ETHTOOL_GREGS */
};
/* CMDs currently supported */
#define ETHTOOL_GSET 0x00000001 /* Get settings. */
#define ETHTOOL_SSET 0x00000002 /* Set settings, privileged. */
#define ETHTOOL_GDRVINFO 0x00000003 /* Get driver info. */
+#define ETHTOOL_GREGS 0x00000004 /* Get NIC registers, privileged. */
/* compatibility with older code */
#define SPARC_ETH_GSET ETHTOOL_GSET
Index: linux_2_4/include/linux/mii.h
diff -u linux_2_4/include/linux/mii.h:1.1.1.1 linux_2_4/include/linux/mii.h:1.1.1.1.52.1
--- linux_2_4/include/linux/mii.h:1.1.1.1 Fri May 11 16:54:44 2001
+++ linux_2_4/include/linux/mii.h Sun Jun 10 10:26:44 2001
@@ -126,6 +126,33 @@
#define CSCONFIG_RESV4 0x4000 /* Unused... */
#define CSCONFIG_NDISABLE 0x8000 /* Disable NRZI */
+
+
+struct ethtool_mii_info {
+ struct net_device *dev; /* our net interface */
+ void *useraddr; /* userspace addr to which we put data */
+
+ int phy_id; /* PHY we are addressing */
+
+ int bmcr; /* cached MII register values. */
+ int bmsr; /* -1 means 'undefined', which usually */
+ int advertising; /* means the implementation should read */
+ int lpa; /* the values from hardware instead. */
+
+ int autoneg; /* 0 (disabled), 1 (enabled), -1 (ask hw) */
+ unsigned int ignore; /* mask of medias we never support, */
+ /* such as 100baseT4 */
+ int speed; /* 10, 100, 1000 or -1 (ask hw) */
+ int full_duplex; /* 0 (no), 1 (yes), -1 (ask hw) */
+ unsigned int port; /* PORT_xxx from linux/ethtool.h */
+
+ int (*mdio_read) (struct net_device *dev, int phy_id, int location);
+ void (*mdio_write) (struct net_device *dev, int phy_id, int location, int val);
+};
+
+int mii_ethtool_gset (struct ethtool_mii_info *mii);
+int mii_ethtool_sset (struct ethtool_mii_info *mii);
+
/**
* mii_nway_result
* @negotiated: value of MII ANAR and'd with ANLPAR
Index: linux_2_4/drivers/net/mii.c
diff -u /dev/null linux_2_4/drivers/net/mii.c:1.1.2.1
--- /dev/null Sun Jun 10 10:28:01 2001
+++ linux_2_4/drivers/net/mii.c Sun Jun 10 10:26:44 2001
@@ -0,0 +1,212 @@
+/*
+ * linux/drivers/net/mii.c
+ * Copyright 2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <asm/uaccess.h>
+
+
+static void mii_fill_ethtool_cmd (struct net_device *dev,
+ struct ethtool_mii_info *mii,
+ struct ethtool_cmd *ecmd)
+{
+ unsigned int bmsr, bmcr, v, autoneg, advertising, lpa;
+ unsigned int negotiated, full_duplex, speed;
+
+ memset(ecmd, 0, sizeof(*ecmd));
+
+ ecmd->cmd = ETHTOOL_GSET;
+
+ if (mii->bmcr < 0)
+ bmcr = mii->bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
+ else bmcr = mii->bmcr;
+
+ if (mii->bmsr < 0)
+ bmsr = mii->bmsr = mii->mdio_read(dev, mii->phy_id, MII_BMSR);
+ else bmsr = mii->bmsr;
+
+ if (mii->advertising < 0)
+ advertising = mii->advertising =
+ mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
+ else advertising = mii->advertising;
+
+ if (mii->lpa < 0)
+ lpa = mii->lpa = mii->mdio_read(dev, mii->phy_id, MII_LPA);
+ else lpa = mii->lpa;
+
+ negotiated = advertising & lpa;
+
+ if (mii->autoneg < 0)
+ autoneg = mii->autoneg = (bmcr & BMCR_ANENABLE) ? 1 : 0;
+ else autoneg = mii->autoneg;
+
+ if (mii->full_duplex < 0)
+ full_duplex = mii->full_duplex =
+ mii_nway_result(negotiated) & LPA_DUPLEX;
+ else full_duplex = mii->full_duplex;
+
+ if (mii->speed < 0) {
+ if (negotiated & LPA_100)
+ speed = mii->speed = 100;
+ else
+ speed = mii->speed = 10;
+ } else
+ speed = mii->speed;
+
+ ecmd->supported = SUPPORTED_MII;
+ v = bmsr & ~mii->ignore;
+ if (v & BMSR_10HALF)
+ ecmd->supported |= SUPPORTED_10baseT_Half;
+ if (v & BMSR_10FULL)
+ ecmd->supported |= SUPPORTED_10baseT_Full;
+ if (v & BMSR_100HALF)
+ ecmd->supported |= SUPPORTED_100baseT_Half;
+ if (v & BMSR_100FULL)
+ ecmd->supported |= SUPPORTED_100baseT_Full;
+ if (bmsr & BMSR_ANEGCAPABLE)
+ ecmd->supported |= SUPPORTED_Autoneg;
+ else
+ autoneg = mii->autoneg = 0;
+
+ ecmd->advertising = ADVERTISED_MII;
+ v = advertising & ~mii->ignore;
+ if (v & BMSR_10HALF)
+ ecmd->advertising |= ADVERTISED_10baseT_Half;
+ if (v & BMSR_10FULL)
+ ecmd->advertising |= ADVERTISED_10baseT_Full;
+ if (v & BMSR_100HALF)
+ ecmd->advertising |= ADVERTISED_100baseT_Half;
+ if (v & BMSR_100FULL)
+ ecmd->advertising |= ADVERTISED_100baseT_Full;
+ if (autoneg) {
+ ecmd->advertising |= ADVERTISED_Autoneg;
+ ecmd->autoneg = AUTONEG_ENABLE;
+ } else
+ ecmd->autoneg = AUTONEG_DISABLE;
+
+ ecmd->speed = speed == 100 ? SPEED_100 : SPEED_10;
+ ecmd->duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
+ ecmd->port = PORT_MII;
+ ecmd->phy_address = mii->phy_id;
+ ecmd->transceiver = XCVR_INTERNAL;
+}
+
+int mii_ethtool_gset (struct ethtool_mii_info *mii)
+{
+ struct ethtool_cmd ecmd;
+
+ if (mii->port != PORT_MII)
+ return -EOPNOTSUPP;
+
+ mii_fill_ethtool_cmd(mii->dev, mii, &ecmd);
+
+ if (copy_to_user(mii->useraddr, &ecmd, sizeof(ecmd)))
+ return -EFAULT;
+
+ return 0;
+}
+
+int mii_ethtool_sset (struct ethtool_mii_info *mii)
+{
+ struct net_device *dev = mii->dev;
+ struct ethtool_cmd in, out;
+ unsigned int advert, bmcr;
+
+ if (copy_from_user (&in, mii->useraddr, sizeof (in)))
+ return -EFAULT;
+ mii_fill_ethtool_cmd (dev, mii, &out);
+
+ if (in.port != out.port) {
+ if (copy_to_user(mii->useraddr, &in, sizeof(in)))
+ return -EFAULT;
+ mii->port = in.port;
+ return 0;
+ }
+
+ /* we don't support changing phy address, tranceiver,
+ * or the interrupt mitigation stuff.
+ */
+ if ((in.phy_address != out.phy_address) ||
+ (in.transceiver != XCVR_INTERNAL) ||
+ (in.maxtxpkt != out.maxtxpkt) ||
+ (in.maxrxpkt != out.maxrxpkt))
+ return -EOPNOTSUPP;
+
+ advert = mii->advertising & ~ADVERTISE_ALL;
+
+ /* NWAY autonegotiation enabled */
+ if (in.autoneg == AUTONEG_ENABLE) {
+ bmcr = mii->bmcr | BMCR_ANENABLE;
+
+ if (in.advertising & ADVERTISED_10baseT_Half)
+ advert |= ADVERTISE_10HALF;
+ if (in.advertising & ADVERTISED_10baseT_Full)
+ advert |= ADVERTISE_10FULL;
+ if (in.advertising & ADVERTISED_100baseT_Half)
+ advert |= ADVERTISE_100HALF;
+ if (in.advertising & ADVERTISED_100baseT_Full)
+ advert |= ADVERTISE_100FULL;
+ if (advert == (mii->advertising & ~ADVERTISE_ALL))
+ return -EINVAL;
+ }
+
+ /* NWAY autonegotiation disabled */
+ else {
+ bmcr = mii->bmcr & ~BMCR_ANENABLE;
+
+ if (in.speed == SPEED_100)
+ bmcr |= BMCR_SPEED100;
+ else bmcr &= ~BMCR_SPEED100;
+
+ if (in.duplex == DUPLEX_FULL)
+ bmcr |= BMCR_FULLDPLX;
+ else bmcr &= ~BMCR_FULLDPLX;
+
+ if (mii->bmsr & BMSR_10HALF)
+ advert |= ADVERTISE_10HALF;
+ if (mii->bmsr & BMSR_10FULL)
+ advert |= ADVERTISE_10FULL;
+ if (mii->bmsr & BMSR_100HALF)
+ advert |= ADVERTISE_100HALF;
+ if (mii->bmsr & BMSR_100FULL)
+ advert |= ADVERTISE_100FULL;
+ }
+
+ if (advert != mii->advertising) {
+ bmcr |= BMCR_ANRESTART;
+ mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, advert);
+ mii->advertising = advert;
+ }
+
+ /* some phys need autoneg dis/enabled separately from other settings */
+ if ((bmcr & BMCR_ANENABLE) && (!(mii->bmcr & BMCR_ANENABLE))) {
+ mii->mdio_write(dev, mii->phy_id, MII_BMCR,
+ mii->bmcr | BMCR_ANENABLE | BMCR_ANRESTART);
+ bmcr &= ~BMCR_ANRESTART;
+ } else if ((!(bmcr & BMCR_ANENABLE)) && (mii->bmcr & BMCR_ANENABLE)) {
+ mii->mdio_write(dev, mii->phy_id, MII_BMCR,
+ mii->bmcr & ~BMCR_ANENABLE);
+ }
+
+ if (bmcr != mii->bmcr) {
+ mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
+ bmcr &= ~BMCR_ANRESTART;
+ mii->bmcr = bmcr;
+ }
+
+ if (copy_to_user(mii->useraddr, &out, sizeof(out)))
+ return -EFAULT;
+
+ return 0;
+}
+
+EXPORT_SYMBOL(mii_ethtool_gset);
+EXPORT_SYMBOL(mii_ethtool_sset);
Index: linux_2_4/drivers/net/epic100.c
diff -u linux_2_4/drivers/net/epic100.c:1.1.1.35 linux_2_4/drivers/net/epic100.c:1.1.1.35.42.3
--- linux_2_4/drivers/net/epic100.c:1.1.1.35 Sat May 19 18:56:00 2001
+++ linux_2_4/drivers/net/epic100.c Sun Jun 10 10:26:44 2001
@@ -45,13 +45,16 @@
* { fill me in }
LK1.1.8:
- * ethtool support (jgarzik)
+ * ethtool driver info support (jgarzik)
+ LK1.1.9:
+ * ethtool media get/set support (jgarzik)
+
*/
#define DRV_NAME "epic100"
-#define DRV_VERSION "1.11+LK1.1.8"
-#define DRV_RELDATE "May 18, 2001"
+#define DRV_VERSION "1.11+LK1.1.9"
+#define DRV_RELDATE "June 10, 2001"
/* The user-configurable values.
@@ -116,6 +119,7 @@
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/ethtool.h>
+#include <linux/mii.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -135,6 +139,11 @@
MODULE_PARM(rx_copybreak, "i");
MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
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(rx_copybreak, "EPIC/100 copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(full_duplex, "EPIC/100 full duplex setting(s) (1)");
/*
Theory of Operation
@@ -1169,7 +1178,7 @@
if (pkt_len > PKT_BUF_SZ - 4) {
printk(KERN_ERR "%s: Oversized Ethernet frame, status %x "
"%d bytes.\n",
- dev->name, pkt_len, status);
+ dev->name, status, pkt_len);
pkt_len = 1514;
}
/* Check if the packet is long enough to accept without copying
@@ -1344,27 +1353,72 @@
return;
}
-static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
{
struct epic_private *np = dev->priv;
u32 ethcmd;
-
- if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd)))
+
+ if (copy_from_user (ðcmd, useraddr, sizeof (ethcmd)))
return -EFAULT;
+
+ switch (ethcmd) {
+ case ETHTOOL_GDRVINFO:
+ {
+ struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+ strcpy (info.driver, DRV_NAME);
+ strcpy (info.version, DRV_VERSION);
+ strcpy (info.bus_info, np->pci_dev->slot_name);
+ if (copy_to_user (useraddr, &info, sizeof (info)))
+ return -EFAULT;
+ return 0;
+ }
- switch (ethcmd) {
- case ETHTOOL_GDRVINFO: {
- struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
- strcpy(info.driver, DRV_NAME);
- strcpy(info.version, DRV_VERSION);
- strcpy(info.bus_info, np->pci_dev->slot_name);
- if (copy_to_user(useraddr, &info, sizeof(info)))
- return -EFAULT;
- return 0;
+ case ETHTOOL_GSET:
+ case ETHTOOL_SSET:
+ {
+ struct ethtool_mii_info info = {
+ dev: dev,
+ useraddr: useraddr,
+ phy_id: np->phys[0],
+ bmcr: -1,
+ bmsr: -1,
+ lpa: -1,
+ advertising: np->advertising,
+ autoneg: -1,
+ ignore: ADVERTISE_100BASE4,
+ speed: -1,
+ full_duplex: np->full_duplex,
+ port: PORT_MII,
+ mdio_read: mdio_read,
+ mdio_write: mdio_write,
+ };
+ int rc;
+ unsigned int changed = 0;
+
+ if (ethcmd == ETHTOOL_GSET)
+ rc = mii_ethtool_gset (&info);
+ else
+ rc = mii_ethtool_sset (&info);
+
+ if (np->advertising != info.advertising) {
+ np->advertising = info.advertising;
+ changed = 1;
+ }
+ if (np->full_duplex != info.full_duplex) {
+ np->full_duplex = info.full_duplex;
+ changed = 1;
+ }
+
+ if (changed)
+ check_media (dev);
+
+ return rc;
+ }
+
+ default:
+ break;
}
- }
-
return -EOPNOTSUPP;
}
next reply other threads:[~2001-06-10 17:35 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2001-06-10 17:34 Jeff Garzik [this message]
2001-06-11 5:59 ` PATCH: ethtool MII helpers Pekka Savola
2001-06-11 6:10 ` Keith Owens
2001-06-12 17:09 ` Bogdan Costescu
2001-06-12 17:40 ` Jeff Garzik
2001-06-12 18:40 ` PATCH: ethtool MII helpers (vers 2) Jeff Garzik
2001-06-13 15:29 ` PATCH: ethtool MII helpers Bogdan Costescu
2001-06-13 16:56 ` Donald Becker
2001-06-13 20:24 ` Jeff Garzik
2001-06-15 17:22 ` Bogdan Costescu
2001-06-22 5:10 ` Chris Wedgwood
2001-06-22 5:24 ` Jeff Garzik
2001-06-22 5:34 ` Chris Wedgwood
2001-06-22 5:58 ` Jeff Garzik
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=3B23AFC3.71CE2FD2@mandrakesoft.com \
--to=jgarzik@mandrakesoft.com \
--cc=davem@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@oss.sgi.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.