Commit 10096974 authored by Jeff Garzik's avatar Jeff Garzik Committed by David S. Miller

[netdrvr] ns83820: add ethtool media support

Split out from patch authored by Dan Faerch <dan@hacker.dk>.
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent 2808d2e8
#define VERSION "0.22" #define VERSION "0.23"
/* ns83820.c by Benjamin LaHaise with contributions. /* ns83820.c by Benjamin LaHaise with contributions.
* *
* Questions/comments/discussion to linux-ns83820@kvack.org. * Questions/comments/discussion to linux-ns83820@kvack.org.
...@@ -1247,6 +1247,149 @@ static struct net_device_stats *ns83820_get_stats(struct net_device *ndev) ...@@ -1247,6 +1247,149 @@ static struct net_device_stats *ns83820_get_stats(struct net_device *ndev)
return &dev->stats; return &dev->stats;
} }
/* Let ethtool retrieve info */
static int ns83820_get_settings(struct net_device *ndev,
struct ethtool_cmd *cmd)
{
struct ns83820 *dev = PRIV(ndev);
u32 cfg, tanar, tbicr;
int have_optical = 0;
int fullduplex = 0;
/*
* Here's the list of available ethtool commands from other drivers:
* cmd->advertising =
* cmd->speed =
* cmd->duplex =
* cmd->port = 0;
* cmd->phy_address =
* cmd->transceiver = 0;
* cmd->autoneg =
* cmd->maxtxpkt = 0;
* cmd->maxrxpkt = 0;
*/
/* read current configuration */
cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY;
tanar = readl(dev->base + TANAR);
tbicr = readl(dev->base + TBICR);
if (dev->CFG_cache & CFG_TBI_EN) {
/* we have an optical interface */
have_optical = 1;
fullduplex = (cfg & CFG_DUPSTS) ? 1 : 0;
} else {
/* We have copper */
fullduplex = (cfg & CFG_DUPSTS) ? 1 : 0;
}
cmd->supported = SUPPORTED_Autoneg;
/* we have optical interface */
if (dev->CFG_cache & CFG_TBI_EN) {
cmd->supported |= SUPPORTED_1000baseT_Half |
SUPPORTED_1000baseT_Full |
SUPPORTED_FIBRE;
cmd->port = PORT_FIBRE;
} /* TODO: else copper related support */
cmd->duplex = fullduplex ? DUPLEX_FULL : DUPLEX_HALF;
switch (cfg / CFG_SPDSTS0 & 3) {
case 2:
cmd->speed = SPEED_1000;
break;
case 1:
cmd->speed = SPEED_100;
break;
default:
cmd->speed = SPEED_10;
break;
}
cmd->autoneg = (tbicr & TBICR_MR_AN_ENABLE) ? 1: 0;
return 0;
}
/* Let ethool change settings*/
static int ns83820_set_settings(struct net_device *ndev,
struct ethtool_cmd *cmd)
{
struct ns83820 *dev = PRIV(ndev);
u32 cfg, tanar;
int have_optical = 0;
int fullduplex = 0;
/* read current configuration */
cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY;
tanar = readl(dev->base + TANAR);
if (dev->CFG_cache & CFG_TBI_EN) {
/* we have optical */
have_optical = 1;
fullduplex = (tanar & TANAR_FULL_DUP);
} else {
/* we have copper */
fullduplex = cfg & CFG_DUPSTS;
}
spin_lock_irq(&dev->misc_lock);
spin_lock(&dev->tx_lock);
/* Set duplex */
if (cmd->duplex != fullduplex) {
if (have_optical) {
/*set full duplex*/
if (cmd->duplex == DUPLEX_FULL) {
/* force full duplex */
writel(readl(dev->base + TXCFG)
| TXCFG_CSI | TXCFG_HBI | TXCFG_ATP,
dev->base + TXCFG);
writel(readl(dev->base + RXCFG) | RXCFG_RX_FD,
dev->base + RXCFG);
/* Light up full duplex LED */
writel(readl(dev->base + GPIOR) | GPIOR_GP1_OUT,
dev->base + GPIOR);
} else {
/*TODO: set half duplex */
}
} else {
/*we have copper*/
/* TODO: Set duplex for copper cards */
}
printk(KERN_INFO "%s: Duplex set via ethtool\n",
ndev->name);
}
/* Set autonegotiation */
if (1) {
if (cmd->autoneg == AUTONEG_ENABLE) {
/* restart auto negotiation */
writel(TBICR_MR_AN_ENABLE | TBICR_MR_RESTART_AN,
dev->base + TBICR);
writel(TBICR_MR_AN_ENABLE, dev->base + TBICR);
dev->linkstate = LINK_AUTONEGOTIATE;
printk(KERN_INFO "%s: autoneg enabled via ethtool\n",
ndev->name);
} else {
/* disable auto negotiation */
writel(0x00000000, dev->base + TBICR);
}
printk(KERN_INFO "%s: autoneg %s via ethtool\n", ndev->name,
cmd->autoneg ? "ENABLED" : "DISABLED");
}
phy_intr(ndev);
spin_unlock(&dev->tx_lock);
spin_unlock_irq(&dev->misc_lock);
return 0;
}
/* end ethtool get/set support -df */
static void ns83820_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info) static void ns83820_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info)
{ {
struct ns83820 *dev = PRIV(ndev); struct ns83820 *dev = PRIV(ndev);
...@@ -1263,6 +1406,8 @@ static u32 ns83820_get_link(struct net_device *ndev) ...@@ -1263,6 +1406,8 @@ static u32 ns83820_get_link(struct net_device *ndev)
} }
static const struct ethtool_ops ops = { static const struct ethtool_ops ops = {
.get_settings = ns83820_get_settings,
.set_settings = ns83820_set_settings,
.get_drvinfo = ns83820_get_drvinfo, .get_drvinfo = ns83820_get_drvinfo,
.get_link = ns83820_get_link .get_link = ns83820_get_link
}; };
......
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