Commit c48ce926 authored by David S. Miller's avatar David S. Miller

[SPARC]: Update ethtool support in Sun net drivers.

parent 9696b971
/* $Id: sunbmac.c,v 1.30 2002/01/15 06:48:55 davem Exp $
* sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters.
*
* Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
* Copyright (C) 1997, 1998, 1999, 2003 David S. Miller (davem@redhat.com)
*/
#include <linux/module.h>
......@@ -18,6 +18,7 @@
#include <linux/init.h>
#include <linux/crc32.h>
#include <linux/errno.h>
#include <linux/ethtool.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
......@@ -37,7 +38,7 @@
#include "sunbmac.h"
static char version[] __initdata =
"sunbmac.c:v1.9 11/Sep/99 David S. Miller (davem@redhat.com)\n";
"sunbmac.c:v2.0 24/Nov/03 David S. Miller (davem@redhat.com)\n";
#undef DEBUG_PROBE
#undef DEBUG_TX
......@@ -1035,6 +1036,33 @@ static void bigmac_set_multicast(struct net_device *dev)
sbus_writel(tmp, bregs + BMAC_RXCFG);
}
/* Ethtool support... */
static void bigmac_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
struct bigmac *bp = dev->priv;
strcpy(info->driver, "sunbmac");
strcpy(info->version, "2.0");
sprintf(info->bus_info, "SBUS:%d",
bp->qec_sdev->slot);
}
static u32 bigmac_get_link(struct net_device *dev)
{
struct bigmac *bp = dev->priv;
spin_lock_irq(&bp->lock);
bp->sw_bmsr = bigmac_tcvr_read(bp, bp->tregs, BIGMAC_BMSR);
spin_unlock_irq(&bp->lock);
return (bp->sw_bmsr & BMSR_LSTATUS);
}
static struct ethtool_ops bigmac_ethtool_ops = {
.get_drvinfo = bigmac_get_drvinfo,
.get_link = bigmac_get_link,
};
static int __init bigmac_ether_init(struct sbus_dev *qec_sdev)
{
struct net_device *dev;
......@@ -1169,6 +1197,7 @@ static int __init bigmac_ether_init(struct sbus_dev *qec_sdev)
dev->open = &bigmac_open;
dev->stop = &bigmac_close;
dev->hard_start_xmit = &bigmac_start_xmit;
dev->ethtool_ops = &bigmac_ethtool_ops;
/* Set links to BigMAC statistic and multi-cast loading code. */
dev->get_stats = &bigmac_get_stats;
......
/* $Id: sungem.c,v 1.44.2.22 2002/03/13 01:18:12 davem Exp $
* sungem.c: Sun GEM ethernet driver.
*
* Copyright (C) 2000, 2001, 2002 David S. Miller (davem@redhat.com)
* Copyright (C) 2000, 2001, 2002, 2003 David S. Miller (davem@redhat.com)
*
* Support for Apple GMAC and assorted PHYs by
* Benjamin Herrenscmidt (benh@kernel.crashing.org)
......@@ -70,8 +70,8 @@
SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)
#define DRV_NAME "sungem"
#define DRV_VERSION "0.97"
#define DRV_RELDATE "3/20/02"
#define DRV_VERSION "0.98"
#define DRV_RELDATE "8/24/03"
#define DRV_AUTHOR "David S. Miller (davem@redhat.com)"
static char version[] __devinitdata =
......@@ -2317,177 +2317,134 @@ static void gem_set_multicast(struct net_device *dev)
spin_unlock_irq(&gp->lock);
}
/* Eventually add support for changing the advertisement
* on autoneg.
*/
static int gem_ethtool_ioctl(struct net_device *dev, void *ep_user)
static void gem_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
struct gem *gp = dev->priv;
strcpy(info->driver, DRV_NAME);
strcpy(info->version, DRV_VERSION);
strcpy(info->bus_info, pci_name(gp->pdev));
}
static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct gem *gp = dev->priv;
struct ethtool_cmd ecmd;
if (copy_from_user(&ecmd, ep_user, sizeof(ecmd)))
return -EFAULT;
switch(ecmd.cmd) {
case ETHTOOL_GDRVINFO: {
struct ethtool_drvinfo info = { .cmd = ETHTOOL_GDRVINFO };
strncpy(info.driver, DRV_NAME, ETHTOOL_BUSINFO_LEN);
strncpy(info.version, DRV_VERSION, ETHTOOL_BUSINFO_LEN);
info.fw_version[0] = '\0';
strncpy(info.bus_info, pci_name(gp->pdev), ETHTOOL_BUSINFO_LEN);
info.regdump_len = 0; /*SUNGEM_NREGS;*/
if (gp->phy_type == phy_mii_mdio0 ||
gp->phy_type == phy_mii_mdio1) {
if (gp->phy_mii.def)
cmd->supported = gp->phy_mii.def->features;
else
cmd->supported = (SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full);
if (copy_to_user(ep_user, &info, sizeof(info)))
return -EFAULT;
/* XXX hardcoded stuff for now */
cmd->port = PORT_MII;
cmd->transceiver = XCVR_EXTERNAL;
cmd->phy_address = 0; /* XXX fixed PHYAD */
return 0;
}
case ETHTOOL_GSET:
if (gp->phy_type == phy_mii_mdio0 ||
gp->phy_type == phy_mii_mdio1) {
if (gp->phy_mii.def)
ecmd.supported = gp->phy_mii.def->features;
else
ecmd.supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full;
/* XXX hardcoded stuff for now */
ecmd.port = PORT_MII;
ecmd.transceiver = XCVR_EXTERNAL;
ecmd.phy_address = 0; /* XXX fixed PHYAD */
/* Return current PHY settings */
spin_lock_irq(&gp->lock);
ecmd.autoneg = gp->want_autoneg;
ecmd.speed = gp->phy_mii.speed;
ecmd.duplex = gp->phy_mii.duplex;
ecmd.advertising = gp->phy_mii.advertising;
/* If we started with a forced mode, we don't have a default
* advertise set, we need to return something sensible so
* userland can re-enable autoneg properly */
if (ecmd.advertising == 0)
ecmd.advertising = ecmd.supported;
spin_unlock_irq(&gp->lock);
} else { // XXX PCS ?
ecmd.supported =
/* Return current PHY settings */
spin_lock_irq(&gp->lock);
cmd->autoneg = gp->want_autoneg;
cmd->speed = gp->phy_mii.speed;
cmd->duplex = gp->phy_mii.duplex;
cmd->advertising = gp->phy_mii.advertising;
/* If we started with a forced mode, we don't have a default
* advertise set, we need to return something sensible so
* userland can re-enable autoneg properly.
*/
if (cmd->advertising == 0)
cmd->advertising = cmd->supported;
spin_unlock_irq(&gp->lock);
} else { // XXX PCS ?
cmd->supported =
(SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
SUPPORTED_Autoneg);
ecmd.advertising = ecmd.supported;
}
if (copy_to_user(ep_user, &ecmd, sizeof(ecmd)))
return -EFAULT;
return 0;
case ETHTOOL_SSET:
/* Verify the settings we care about. */
if (ecmd.autoneg != AUTONEG_ENABLE &&
ecmd.autoneg != AUTONEG_DISABLE)
return -EINVAL;
if (ecmd.autoneg == AUTONEG_ENABLE &&
ecmd.advertising == 0)
return -EINVAL;
if (ecmd.autoneg == AUTONEG_DISABLE &&
((ecmd.speed != SPEED_1000 &&
ecmd.speed != SPEED_100 &&
ecmd.speed != SPEED_10) ||
(ecmd.duplex != DUPLEX_HALF &&
ecmd.duplex != DUPLEX_FULL)))
return -EINVAL;
/* Apply settings and restart link process. */
spin_lock_irq(&gp->lock);
gem_begin_auto_negotiation(gp, &ecmd);
spin_unlock_irq(&gp->lock);
return 0;
case ETHTOOL_NWAY_RST:
if (!gp->want_autoneg)
return -EINVAL;
cmd->advertising = cmd->supported;
cmd->speed = 0;
cmd->duplex = cmd->port = cmd->phy_address =
cmd->transceiver = cmd->autoneg = 0;
}
cmd->maxtxpkt = cmd->maxrxpkt = 0;
/* Restart link process. */
spin_lock_irq(&gp->lock);
gem_begin_auto_negotiation(gp, NULL);
spin_unlock_irq(&gp->lock);
return 0;
}
return 0;
static int gem_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct gem *gp = dev->priv;
case ETHTOOL_GWOL:
case ETHTOOL_SWOL:
break; /* todo */
/* Verify the settings we care about. */
if (cmd->autoneg != AUTONEG_ENABLE &&
cmd->autoneg != AUTONEG_DISABLE)
return -EINVAL;
/* get link status */
case ETHTOOL_GLINK: {
struct ethtool_value edata = { .cmd = ETHTOOL_GLINK };
if (cmd->autoneg == AUTONEG_ENABLE &&
cmd->advertising == 0)
return -EINVAL;
edata.data = (gp->lstate == link_up);
if (copy_to_user(ep_user, &edata, sizeof(edata)))
return -EFAULT;
return 0;
}
if (cmd->autoneg == AUTONEG_DISABLE &&
((cmd->speed != SPEED_1000 &&
cmd->speed != SPEED_100 &&
cmd->speed != SPEED_10) ||
(cmd->duplex != DUPLEX_HALF &&
cmd->duplex != DUPLEX_FULL)))
return -EINVAL;
/* Apply settings and restart link process. */
spin_lock_irq(&gp->lock);
gem_begin_auto_negotiation(gp, cmd);
spin_unlock_irq(&gp->lock);
/* get message-level */
case ETHTOOL_GMSGLVL: {
struct ethtool_value edata = { .cmd = ETHTOOL_GMSGLVL };
return 0;
}
edata.data = gp->msg_enable;
if (copy_to_user(ep_user, &edata, sizeof(edata)))
return -EFAULT;
return 0;
}
static int gem_nway_reset(struct net_device *dev)
{
struct gem *gp = dev->priv;
/* set message-level */
case ETHTOOL_SMSGLVL: {
struct ethtool_value edata;
if (!gp->want_autoneg)
return -EINVAL;
if (copy_from_user(&edata, ep_user, sizeof(edata)))
return -EFAULT;
gp->msg_enable = edata.data;
return 0;
}
/* Restart link process. */
spin_lock_irq(&gp->lock);
gem_begin_auto_negotiation(gp, NULL);
spin_unlock_irq(&gp->lock);
#if 0
case ETHTOOL_GREGS: {
struct ethtool_regs regs;
u32 *regbuf;
int r = 0;
return 0;
}
if (copy_from_user(&regs, useraddr, sizeof(regs)))
return -EFAULT;
if (regs.len > SUNGEM_NREGS) {
regs.len = SUNGEM_NREGS;
}
regs.version = 0;
if (copy_to_user(useraddr, &regs, sizeof(regs)))
return -EFAULT;
static u32 gem_get_link(struct net_device *dev)
{
struct gem *gp = dev->priv;
if (!gp->hw_running)
return -ENODEV;
useraddr += offsetof(struct ethtool_regs, data);
/* Use kmalloc to avoid bloating the stack */
regbuf = kmalloc(4 * SUNGEM_NREGS, GFP_KERNEL);
if (!regbuf)
return -ENOMEM;
spin_lock_irq(&np->lock);
gem_get_regs(gp, regbuf);
spin_unlock_irq(&np->lock);
if (copy_to_user(useraddr, regbuf, regs.len*sizeof(u32)))
r = -EFAULT;
kfree(regbuf);
return r;
}
#endif
};
return (gp->lstate == link_up);
}
return -EOPNOTSUPP;
static u32 gem_get_msglevel(struct net_device *dev)
{
struct gem *gp = dev->priv;
return gp->msg_enable;
}
static void gem_set_msglevel(struct net_device *dev, u32 value)
{
struct gem *gp = dev->priv;
gp->msg_enable = value;
}
static struct ethtool_ops gem_ethtool_ops = {
.get_drvinfo = gem_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_settings = gem_get_settings,
.set_settings = gem_set_settings,
.nway_reset = gem_nway_reset,
.get_link = gem_get_link,
.get_msglevel = gem_get_msglevel,
.set_msglevel = gem_set_msglevel,
};
static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
......@@ -2501,10 +2458,6 @@ static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
down(&gp->pm_sem);
switch (cmd) {
case SIOCETHTOOL:
rc = gem_ethtool_ioctl(dev, ifr->ifr_data);
break;
case SIOCGMIIPHY: /* Get address of MII PHY in use. */
data->phy_id = gp->mii_phy_addr;
/* Fallthrough... */
......@@ -2812,6 +2765,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
dev->get_stats = gem_get_stats;
dev->set_multicast_list = gem_set_multicast;
dev->do_ioctl = gem_ioctl;
dev->ethtool_ops = &gem_ethtool_ops;
dev->tx_timeout = gem_tx_timeout;
dev->watchdog_timeo = 5 * HZ;
dev->change_mtu = gem_change_mtu;
......
......@@ -3,7 +3,7 @@
* auto carrier detecting ethernet driver. Also known as the
* "Happy Meal Ethernet" found on SunSwift SBUS cards.
*
* Copyright (C) 1996, 1998, 1999, 2002 David S. Miller (davem@redhat.com)
* Copyright (C) 1996, 1998, 1999, 2002, 2003 David S. Miller (davem@redhat.com)
*
* Changes :
* 2000/11/11 Willy Tarreau <willy AT meta-x.org>
......@@ -14,7 +14,7 @@
*/
static char version[] =
"sunhme.c:v2.01 26/Mar/2002 David S. Miller (davem@redhat.com)\n";
"sunhme.c:v2.02 24/Aug/2003 David S. Miller (davem@redhat.com)\n";
#include <linux/module.h>
#include <linux/config.h>
......@@ -2426,85 +2426,109 @@ static void happy_meal_set_multicast(struct net_device *dev)
}
/* Ethtool support... */
static int happy_meal_ioctl(struct net_device *dev,
struct ifreq *rq, int cmd)
static int hme_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct happy_meal *hp = dev->priv;
struct ethtool_cmd *ep_user = (struct ethtool_cmd *) rq->ifr_data;
struct ethtool_cmd ecmd;
if (cmd != SIOCETHTOOL)
return -EOPNOTSUPP;
if (copy_from_user(&ecmd, ep_user, sizeof(ecmd)))
return -EFAULT;
if (ecmd.cmd == ETHTOOL_GSET) {
ecmd.supported =
(SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
/* XXX hardcoded stuff for now */
ecmd.port = PORT_TP; /* XXX no MII support */
ecmd.transceiver = XCVR_INTERNAL; /* XXX no external xcvr support */
ecmd.phy_address = 0; /* XXX fixed PHYAD */
/* Record PHY settings. */
spin_lock_irq(&hp->happy_lock);
hp->sw_bmcr = happy_meal_tcvr_read(hp, hp->tcvregs, MII_BMCR);
hp->sw_lpa = happy_meal_tcvr_read(hp, hp->tcvregs, MII_LPA);
spin_unlock_irq(&hp->happy_lock);
if (hp->sw_bmcr & BMCR_ANENABLE) {
ecmd.autoneg = AUTONEG_ENABLE;
ecmd.speed =
(hp->sw_lpa & (LPA_100HALF | LPA_100FULL)) ?
SPEED_100 : SPEED_10;
if (ecmd.speed == SPEED_100)
ecmd.duplex =
(hp->sw_lpa & (LPA_100FULL)) ?
DUPLEX_FULL : DUPLEX_HALF;
else
ecmd.duplex =
(hp->sw_lpa & (LPA_10FULL)) ?
DUPLEX_FULL : DUPLEX_HALF;
} else {
ecmd.autoneg = AUTONEG_DISABLE;
ecmd.speed =
(hp->sw_bmcr & BMCR_SPEED100) ?
SPEED_100 : SPEED_10;
ecmd.duplex =
(hp->sw_bmcr & BMCR_FULLDPLX) ?
cmd->supported =
(SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
/* XXX hardcoded stuff for now */
cmd->port = PORT_TP; /* XXX no MII support */
cmd->transceiver = XCVR_INTERNAL; /* XXX no external xcvr support */
cmd->phy_address = 0; /* XXX fixed PHYAD */
/* Record PHY settings. */
spin_lock_irq(&hp->happy_lock);
hp->sw_bmcr = happy_meal_tcvr_read(hp, hp->tcvregs, MII_BMCR);
hp->sw_lpa = happy_meal_tcvr_read(hp, hp->tcvregs, MII_LPA);
spin_unlock_irq(&hp->happy_lock);
if (hp->sw_bmcr & BMCR_ANENABLE) {
cmd->autoneg = AUTONEG_ENABLE;
cmd->speed =
(hp->sw_lpa & (LPA_100HALF | LPA_100FULL)) ?
SPEED_100 : SPEED_10;
if (cmd->speed == SPEED_100)
cmd->duplex =
(hp->sw_lpa & (LPA_100FULL)) ?
DUPLEX_FULL : DUPLEX_HALF;
}
if (copy_to_user(ep_user, &ecmd, sizeof(ecmd)))
return -EFAULT;
return 0;
} else if (ecmd.cmd == ETHTOOL_SSET) {
/* Verify the settings we care about. */
if (ecmd.autoneg != AUTONEG_ENABLE &&
ecmd.autoneg != AUTONEG_DISABLE)
return -EINVAL;
if (ecmd.autoneg == AUTONEG_DISABLE &&
((ecmd.speed != SPEED_100 &&
ecmd.speed != SPEED_10) ||
(ecmd.duplex != DUPLEX_HALF &&
ecmd.duplex != DUPLEX_FULL)))
return -EINVAL;
/* Ok, do it to it. */
spin_lock_irq(&hp->happy_lock);
del_timer(&hp->happy_timer);
happy_meal_begin_auto_negotiation(hp,
hp->tcvregs,
&ecmd);
spin_unlock_irq(&hp->happy_lock);
else
cmd->duplex =
(hp->sw_lpa & (LPA_10FULL)) ?
DUPLEX_FULL : DUPLEX_HALF;
} else {
cmd->autoneg = AUTONEG_DISABLE;
cmd->speed =
(hp->sw_bmcr & BMCR_SPEED100) ?
SPEED_100 : SPEED_10;
cmd->duplex =
(hp->sw_bmcr & BMCR_FULLDPLX) ?
DUPLEX_FULL : DUPLEX_HALF;
}
return 0;
}
return 0;
} else
return -EOPNOTSUPP;
static int hme_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct happy_meal *hp = dev->priv;
/* Verify the settings we care about. */
if (cmd->autoneg != AUTONEG_ENABLE &&
cmd->autoneg != AUTONEG_DISABLE)
return -EINVAL;
if (cmd->autoneg == AUTONEG_DISABLE &&
((cmd->speed != SPEED_100 &&
cmd->speed != SPEED_10) ||
(cmd->duplex != DUPLEX_HALF &&
cmd->duplex != DUPLEX_FULL)))
return -EINVAL;
/* Ok, do it to it. */
spin_lock_irq(&hp->happy_lock);
del_timer(&hp->happy_timer);
happy_meal_begin_auto_negotiation(hp, hp->tcvregs, cmd);
spin_unlock_irq(&hp->happy_lock);
return 0;
}
static void hme_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
struct happy_meal *hp = dev->priv;
strcpy(info->driver, "sunhme");
strcpy(info->version, "2.02");
if (hp->happy_flags & HFLAG_PCI) {
struct pci_dev *pdev = hp->happy_dev;
strcpy(info->bus_info, pci_name(pdev));
} else {
struct sbus_dev *sdev = hp->happy_dev;
sprintf(info->bus_info, "SBUS:%d",
sdev->slot);
}
}
static u32 hme_get_link(struct net_device *dev)
{
struct happy_meal *hp = dev->priv;
spin_lock_irq(&hp->happy_lock);
hp->sw_bmcr = happy_meal_tcvr_read(hp, hp->tcvregs, MII_BMCR);
spin_unlock_irq(&hp->happy_lock);
return (hp->sw_bmsr & BMSR_LSTATUS);
}
static struct ethtool_ops hme_ethtool_ops = {
.get_settings = hme_get_settings,
.set_settings = hme_set_settings,
.get_drvinfo = hme_get_drvinfo,
.get_link = hme_get_link,
};
static int hme_version_printed;
#ifdef CONFIG_SBUS
......@@ -2797,7 +2821,7 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
dev->set_multicast_list = &happy_meal_set_multicast;
dev->tx_timeout = &happy_meal_tx_timeout;
dev->watchdog_timeo = 5*HZ;
dev->do_ioctl = &happy_meal_ioctl;
dev->ethtool_ops = &hme_ethtool_ops;
/* Happy Meal can do it all... except VLAN. */
dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_VLAN_CHALLENGED;
......@@ -3141,7 +3165,7 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
dev->set_multicast_list = &happy_meal_set_multicast;
dev->tx_timeout = &happy_meal_tx_timeout;
dev->watchdog_timeo = 5*HZ;
dev->do_ioctl = &happy_meal_ioctl;
dev->ethtool_ops = &hme_ethtool_ops;
dev->irq = pdev->irq;
dev->dma = 0;
......
......@@ -70,7 +70,7 @@
#undef DEBUG_DRIVER
static char version[] =
"sunlance.c:v2.01 08/Nov/01 Miguel de Icaza (miguel@nuclecu.unam.mx)\n";
"sunlance.c:v2.02 24/Aug/03 Miguel de Icaza (miguel@nuclecu.unam.mx)\n";
static char lancestr[] = "LANCE";
......@@ -93,6 +93,7 @@ static char lancestr[] = "LANCE";
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/ethtool.h>
#include <asm/system.h>
#include <asm/bitops.h>
......@@ -1287,6 +1288,30 @@ static void lance_free_hwresources(struct lance_private *lp)
}
}
/* Ethtool support... */
static void sparc_lance_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
struct lance_private *lp = dev->priv;
strcpy(info->driver, "sunlance");
strcpy(info->version, "2.02");
sprintf(info->bus_info, "SBUS:%d",
lp->sdev->slot);
}
static u32 sparc_lance_get_link(struct net_device *dev)
{
/* We really do not keep track of this, but this
* is better than not reporting anything at all.
*/
return 1;
}
static struct ethtool_ops sparc_lance_ethtool_ops = {
.get_drvinfo = sparc_lance_get_drvinfo,
.get_link = sparc_lance_get_link,
};
static int __init sparc_lance_init(struct net_device *dev,
struct sbus_dev *sdev,
struct sbus_dma *ledma,
......@@ -1456,6 +1481,7 @@ static int __init sparc_lance_init(struct net_device *dev,
dev->watchdog_timeo = 5*HZ;
dev->get_stats = &lance_get_stats;
dev->set_multicast_list = &lance_set_multicast;
dev->ethtool_ops = &sparc_lance_ethtool_ops;
dev->irq = sdev->irqs[0];
......
......@@ -4,11 +4,11 @@
* controller out there can be most efficiently programmed
* if you make it look like a LANCE.
*
* Copyright (C) 1996, 1999 David S. Miller (davem@redhat.com)
* Copyright (C) 1996, 1999, 2003 David S. Miller (davem@redhat.com)
*/
static char version[] =
"sunqe.c:v2.9 9/11/99 David S. Miller (davem@redhat.com)\n";
"sunqe.c:v3.0 8/24/03 David S. Miller (davem@redhat.com)\n";
#include <linux/module.h>
#include <linux/kernel.h>
......@@ -26,6 +26,7 @@ static char version[] =
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/ethtool.h>
#include <asm/system.h>
#include <asm/bitops.h>
......@@ -684,6 +685,35 @@ static void qe_set_multicast(struct net_device *dev)
netif_wake_queue(dev);
}
/* Ethtool support... */
static void qe_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
struct sunqe *qep = dev->priv;
strcpy(info->driver, "sunqe");
strcpy(info->version, "3.0");
sprintf(info->bus_info, "SBUS:%d",
qep->qe_sdev->slot);
}
static u32 qe_get_link(struct net_device *dev)
{
struct sunqe *qep = dev->priv;
unsigned long mregs = qep->mregs;
u8 phyconfig;
spin_lock_irq(&qep->lock);
phyconfig = sbus_readb(mregs + MREGS_PHYCONFIG);
spin_unlock_irq(&qep->lock);
return (phyconfig & MREGS_PHYCONFIG_LSTAT);
}
static struct ethtool_ops qe_ethtool_ops = {
.get_drvinfo = qe_get_drvinfo,
.get_link = qe_get_link,
};
/* This is only called once at boot time for each card probed. */
static inline void qec_init_once(struct sunqec *qecp, struct sbus_dev *qsdev)
{
......@@ -850,6 +880,7 @@ static int __init qec_ether_init(struct net_device *dev, struct sbus_dev *sdev)
qe_devs[i]->watchdog_timeo = 5*HZ;
qe_devs[i]->irq = sdev->irqs[0];
qe_devs[i]->dma = 0;
qe_devs[i]->ethtool_ops = &qe_ethtool_ops;
}
/* QEC receives interrupts from each QE, then it sends the actual
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment