Commit a232f767 authored by Al Viro's avatar Al Viro Committed by David S. Miller

[CASSINI]: Convert to ethtool_ops

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 325ed823
...@@ -4423,18 +4423,14 @@ static struct { ...@@ -4423,18 +4423,14 @@ static struct {
#define CAS_REG_LEN (sizeof(ethtool_register_table)/sizeof(int)) #define CAS_REG_LEN (sizeof(ethtool_register_table)/sizeof(int))
#define CAS_MAX_REGS (sizeof (u32)*CAS_REG_LEN) #define CAS_MAX_REGS (sizeof (u32)*CAS_REG_LEN)
static u8 *cas_get_regs(struct cas *cp) static void cas_read_regs(struct cas *cp, u8 *ptr, int len)
{ {
u8 *ptr = kmalloc(CAS_MAX_REGS, GFP_KERNEL);
u8 *p; u8 *p;
int i; int i;
unsigned long flags; unsigned long flags;
if (!ptr)
return NULL;
spin_lock_irqsave(&cp->lock, flags); spin_lock_irqsave(&cp->lock, flags);
for (i = 0, p = ptr; i < CAS_REG_LEN ; i ++, p += sizeof(u32)) { for (i = 0, p = ptr; i < len ; i ++, p += sizeof(u32)) {
u16 hval; u16 hval;
u32 val; u32 val;
if (ethtool_register_table[i].offsets < 0) { if (ethtool_register_table[i].offsets < 0) {
...@@ -4447,8 +4443,6 @@ static u8 *cas_get_regs(struct cas *cp) ...@@ -4447,8 +4443,6 @@ static u8 *cas_get_regs(struct cas *cp)
memcpy(p, (u8 *)&val, sizeof(u32)); memcpy(p, (u8 *)&val, sizeof(u32));
} }
spin_unlock_irqrestore(&cp->lock, flags); spin_unlock_irqrestore(&cp->lock, flags);
return ptr;
} }
static struct net_device_stats *cas_get_stats(struct net_device *dev) static struct net_device_stats *cas_get_stats(struct net_device *dev)
...@@ -4561,47 +4555,31 @@ static void cas_set_multicast(struct net_device *dev) ...@@ -4561,47 +4555,31 @@ static void cas_set_multicast(struct net_device *dev)
spin_unlock_irqrestore(&cp->lock, flags); spin_unlock_irqrestore(&cp->lock, flags);
} }
/* Eventually add support for changing the advertisement static void cas_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
* on autoneg. {
*/ struct cas *cp = netdev_priv(dev);
static int cas_ethtool_ioctl(struct net_device *dev, void __user *ep_user) strncpy(info->driver, DRV_MODULE_NAME, ETHTOOL_BUSINFO_LEN);
strncpy(info->version, DRV_MODULE_VERSION, ETHTOOL_BUSINFO_LEN);
info->fw_version[0] = '\0';
strncpy(info->bus_info, pci_name(cp->pdev), ETHTOOL_BUSINFO_LEN);
info->regdump_len = cp->casreg_len < CAS_MAX_REGS ?
cp->casreg_len : CAS_MAX_REGS;
info->n_stats = CAS_NUM_STAT_KEYS;
}
static int cas_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{ {
struct cas *cp = netdev_priv(dev); struct cas *cp = netdev_priv(dev);
u16 bmcr; u16 bmcr;
int full_duplex, speed, pause; int full_duplex, speed, pause;
struct ethtool_cmd ecmd;
unsigned long flags; unsigned long flags;
enum link_state linkstate = link_up; enum link_state linkstate = link_up;
if (copy_from_user(&ecmd, ep_user, sizeof(ecmd))) cmd->advertising = 0;
return -EFAULT; cmd->supported = SUPPORTED_Autoneg;
switch(ecmd.cmd) {
case ETHTOOL_GDRVINFO: {
struct ethtool_drvinfo info = { .cmd = ETHTOOL_GDRVINFO };
strncpy(info.driver, DRV_MODULE_NAME,
ETHTOOL_BUSINFO_LEN);
strncpy(info.version, DRV_MODULE_VERSION,
ETHTOOL_BUSINFO_LEN);
info.fw_version[0] = '\0';
strncpy(info.bus_info, pci_name(cp->pdev),
ETHTOOL_BUSINFO_LEN);
info.regdump_len = cp->casreg_len < CAS_MAX_REGS ?
cp->casreg_len : CAS_MAX_REGS;
info.n_stats = CAS_NUM_STAT_KEYS;
if (copy_to_user(ep_user, &info, sizeof(info)))
return -EFAULT;
return 0;
}
case ETHTOOL_GSET:
ecmd.advertising = 0;
ecmd.supported = SUPPORTED_Autoneg;
if (cp->cas_flags & CAS_FLAG_1000MB_CAP) { if (cp->cas_flags & CAS_FLAG_1000MB_CAP) {
ecmd.supported |= SUPPORTED_1000baseT_Full; cmd->supported |= SUPPORTED_1000baseT_Full;
ecmd.advertising |= ADVERTISED_1000baseT_Full; cmd->advertising |= ADVERTISED_1000baseT_Full;
} }
/* Record PHY settings if HW is on. */ /* Record PHY settings if HW is on. */
...@@ -4609,17 +4587,17 @@ static int cas_ethtool_ioctl(struct net_device *dev, void __user *ep_user) ...@@ -4609,17 +4587,17 @@ static int cas_ethtool_ioctl(struct net_device *dev, void __user *ep_user)
bmcr = 0; bmcr = 0;
linkstate = cp->lstate; linkstate = cp->lstate;
if (CAS_PHY_MII(cp->phy_type)) { if (CAS_PHY_MII(cp->phy_type)) {
ecmd.port = PORT_MII; cmd->port = PORT_MII;
ecmd.transceiver = (cp->cas_flags & CAS_FLAG_SATURN) ? cmd->transceiver = (cp->cas_flags & CAS_FLAG_SATURN) ?
XCVR_INTERNAL : XCVR_EXTERNAL; XCVR_INTERNAL : XCVR_EXTERNAL;
ecmd.phy_address = cp->phy_addr; cmd->phy_address = cp->phy_addr;
ecmd.advertising |= ADVERTISED_TP | ADVERTISED_MII | cmd->advertising |= ADVERTISED_TP | ADVERTISED_MII |
ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Half |
ADVERTISED_10baseT_Full | ADVERTISED_10baseT_Full |
ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Half |
ADVERTISED_100baseT_Full; ADVERTISED_100baseT_Full;
ecmd.supported |= cmd->supported |=
(SUPPORTED_10baseT_Half | (SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full | SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Half |
...@@ -4635,11 +4613,11 @@ static int cas_ethtool_ioctl(struct net_device *dev, void __user *ep_user) ...@@ -4635,11 +4613,11 @@ static int cas_ethtool_ioctl(struct net_device *dev, void __user *ep_user)
} }
} else { } else {
ecmd.port = PORT_FIBRE; cmd->port = PORT_FIBRE;
ecmd.transceiver = XCVR_INTERNAL; cmd->transceiver = XCVR_INTERNAL;
ecmd.phy_address = 0; cmd->phy_address = 0;
ecmd.supported |= SUPPORTED_FIBRE; cmd->supported |= SUPPORTED_FIBRE;
ecmd.advertising |= ADVERTISED_FIBRE; cmd->advertising |= ADVERTISED_FIBRE;
if (cp->hw_running) { if (cp->hw_running) {
/* pcs uses the same bits as mii */ /* pcs uses the same bits as mii */
...@@ -4651,28 +4629,28 @@ static int cas_ethtool_ioctl(struct net_device *dev, void __user *ep_user) ...@@ -4651,28 +4629,28 @@ static int cas_ethtool_ioctl(struct net_device *dev, void __user *ep_user)
spin_unlock_irqrestore(&cp->lock, flags); spin_unlock_irqrestore(&cp->lock, flags);
if (bmcr & BMCR_ANENABLE) { if (bmcr & BMCR_ANENABLE) {
ecmd.advertising |= ADVERTISED_Autoneg; cmd->advertising |= ADVERTISED_Autoneg;
ecmd.autoneg = AUTONEG_ENABLE; cmd->autoneg = AUTONEG_ENABLE;
ecmd.speed = ((speed == 10) ? cmd->speed = ((speed == 10) ?
SPEED_10 : SPEED_10 :
((speed == 1000) ? ((speed == 1000) ?
SPEED_1000 : SPEED_100)); SPEED_1000 : SPEED_100));
ecmd.duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF; cmd->duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
} else { } else {
ecmd.autoneg = AUTONEG_DISABLE; cmd->autoneg = AUTONEG_DISABLE;
ecmd.speed = cmd->speed =
(bmcr & CAS_BMCR_SPEED1000) ? (bmcr & CAS_BMCR_SPEED1000) ?
SPEED_1000 : SPEED_1000 :
((bmcr & BMCR_SPEED100) ? SPEED_100: ((bmcr & BMCR_SPEED100) ? SPEED_100:
SPEED_10); SPEED_10);
ecmd.duplex = cmd->duplex =
(bmcr & BMCR_FULLDPLX) ? (bmcr & BMCR_FULLDPLX) ?
DUPLEX_FULL : DUPLEX_HALF; DUPLEX_FULL : DUPLEX_HALF;
} }
if (linkstate != link_up) { if (linkstate != link_up) {
/* Force these to "unknown" if the link is not up and /* Force these to "unknown" if the link is not up and
* autonogotiation in enabled. We can set the link * autonogotiation in enabled. We can set the link
* speed to 0, but not ecmd.duplex, * speed to 0, but not cmd->duplex,
* because its legal values are 0 and 1. Ethtool will * because its legal values are 0 and 1. Ethtool will
* print the value reported in parentheses after the * print the value reported in parentheses after the
* word "Unknown" for unrecognized values. * word "Unknown" for unrecognized values.
...@@ -4681,47 +4659,52 @@ static int cas_ethtool_ioctl(struct net_device *dev, void __user *ep_user) ...@@ -4681,47 +4659,52 @@ static int cas_ethtool_ioctl(struct net_device *dev, void __user *ep_user)
* settings that we configured. * settings that we configured.
*/ */
if (cp->link_cntl & BMCR_ANENABLE) { if (cp->link_cntl & BMCR_ANENABLE) {
ecmd.speed = 0; cmd->speed = 0;
ecmd.duplex = 0xff; cmd->duplex = 0xff;
} else { } else {
ecmd.speed = SPEED_10; cmd->speed = SPEED_10;
if (cp->link_cntl & BMCR_SPEED100) { if (cp->link_cntl & BMCR_SPEED100) {
ecmd.speed = SPEED_100; cmd->speed = SPEED_100;
} else if (cp->link_cntl & CAS_BMCR_SPEED1000) { } else if (cp->link_cntl & CAS_BMCR_SPEED1000) {
ecmd.speed = SPEED_1000; cmd->speed = SPEED_1000;
} }
ecmd.duplex = (cp->link_cntl & BMCR_FULLDPLX)? cmd->duplex = (cp->link_cntl & BMCR_FULLDPLX)?
DUPLEX_FULL : DUPLEX_HALF; DUPLEX_FULL : DUPLEX_HALF;
} }
} }
if (copy_to_user(ep_user, &ecmd, sizeof(ecmd)))
return -EFAULT;
return 0; return 0;
}
case ETHTOOL_SSET: static int cas_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
if (!capable(CAP_NET_ADMIN)) {
return -EPERM; struct cas *cp = netdev_priv(dev);
unsigned long flags;
/* Verify the settings we care about. */ /* Verify the settings we care about. */
if (ecmd.autoneg != AUTONEG_ENABLE && if (cmd->autoneg != AUTONEG_ENABLE &&
ecmd.autoneg != AUTONEG_DISABLE) cmd->autoneg != AUTONEG_DISABLE)
return -EINVAL; return -EINVAL;
if (ecmd.autoneg == AUTONEG_DISABLE && if (cmd->autoneg == AUTONEG_DISABLE &&
((ecmd.speed != SPEED_1000 && ((cmd->speed != SPEED_1000 &&
ecmd.speed != SPEED_100 && cmd->speed != SPEED_100 &&
ecmd.speed != SPEED_10) || cmd->speed != SPEED_10) ||
(ecmd.duplex != DUPLEX_HALF && (cmd->duplex != DUPLEX_HALF &&
ecmd.duplex != DUPLEX_FULL))) cmd->duplex != DUPLEX_FULL)))
return -EINVAL; return -EINVAL;
/* Apply settings and restart link process. */ /* Apply settings and restart link process. */
spin_lock_irqsave(&cp->lock, flags); spin_lock_irqsave(&cp->lock, flags);
cas_begin_auto_negotiation(cp, &ecmd); cas_begin_auto_negotiation(cp, cmd);
spin_unlock_irqrestore(&cp->lock, flags); spin_unlock_irqrestore(&cp->lock, flags);
return 0; return 0;
}
static int cas_nway_reset(struct net_device *dev)
{
struct cas *cp = netdev_priv(dev);
unsigned long flags;
case ETHTOOL_NWAY_RST:
if ((cp->link_cntl & BMCR_ANENABLE) == 0) if ((cp->link_cntl & BMCR_ANENABLE) == 0)
return -EINVAL; return -EINVAL;
...@@ -4731,146 +4714,92 @@ static int cas_ethtool_ioctl(struct net_device *dev, void __user *ep_user) ...@@ -4731,146 +4714,92 @@ static int cas_ethtool_ioctl(struct net_device *dev, void __user *ep_user)
spin_unlock_irqrestore(&cp->lock, flags); spin_unlock_irqrestore(&cp->lock, flags);
return 0; return 0;
}
case ETHTOOL_GWOL: static u32 cas_get_link(struct net_device *dev)
case ETHTOOL_SWOL: {
break; /* doesn't exist */ struct cas *cp = netdev_priv(dev);
return cp->lstate == link_up;
/* get link status */ }
case ETHTOOL_GLINK: {
struct ethtool_value edata = { .cmd = ETHTOOL_GLINK };
edata.data = (cp->lstate == link_up);
if (copy_to_user(ep_user, &edata, sizeof(edata)))
return -EFAULT;
return 0;
}
/* get message-level */
case ETHTOOL_GMSGLVL: {
struct ethtool_value edata = { .cmd = ETHTOOL_GMSGLVL };
edata.data = cp->msg_enable; static u32 cas_get_msglevel(struct net_device *dev)
if (copy_to_user(ep_user, &edata, sizeof(edata))) {
return -EFAULT; struct cas *cp = netdev_priv(dev);
return 0; return cp->msg_enable;
} }
/* set message-level */ static void cas_set_msglevel(struct net_device *dev, u32 value)
case ETHTOOL_SMSGLVL: { {
struct ethtool_value edata; struct cas *cp = netdev_priv(dev);
cp->msg_enable = value;
}
if (!capable(CAP_NET_ADMIN)) { static int cas_get_regs_len(struct net_device *dev)
return (-EPERM); {
} struct cas *cp = netdev_priv(dev);
if (copy_from_user(&edata, ep_user, sizeof(edata))) return cp->casreg_len < CAS_MAX_REGS ? cp->casreg_len: CAS_MAX_REGS;
return -EFAULT; }
cp->msg_enable = edata.data;
return 0;
}
case ETHTOOL_GREGS: { static void cas_get_regs(struct net_device *dev, struct ethtool_regs *regs,
struct ethtool_regs edata; void *p)
u8 *ptr; {
int len = cp->casreg_len < CAS_MAX_REGS ? struct cas *cp = netdev_priv(dev);
cp->casreg_len: CAS_MAX_REGS; regs->version = 0;
/* cas_read_regs handles locks (cp->lock). */
cas_read_regs(cp, p, regs->len / sizeof(u32));
}
if (copy_from_user(&edata, ep_user, sizeof (edata))) static int cas_get_stats_count(struct net_device *dev)
return -EFAULT; {
return CAS_NUM_STAT_KEYS;
}
if (edata.len > len) static void cas_get_strings(struct net_device *dev, u32 stringset, u8 *data)
edata.len = len; {
edata.version = 0; memcpy(data, &ethtool_cassini_statnames,
if (copy_to_user (ep_user, &edata, sizeof(edata))) CAS_NUM_STAT_KEYS * ETH_GSTRING_LEN);
return -EFAULT; }
/* cas_get_regs handles locks (cp->lock). */ static void cas_get_ethtool_stats(struct net_device *dev,
ptr = cas_get_regs(cp); struct ethtool_stats *estats, u64 *data)
if (ptr == NULL) {
return -ENOMEM; struct cas *cp = netdev_priv(dev);
if (copy_to_user(ep_user + sizeof (edata), ptr, edata.len)) struct net_device_stats *stats = cas_get_stats(cp->dev);
return -EFAULT;
kfree(ptr);
return (0);
}
case ETHTOOL_GSTRINGS: {
struct ethtool_gstrings edata;
int len;
if (copy_from_user(&edata, ep_user, sizeof(edata)))
return -EFAULT;
len = edata.len;
switch(edata.string_set) {
case ETH_SS_STATS:
edata.len = (len < CAS_NUM_STAT_KEYS) ?
len : CAS_NUM_STAT_KEYS;
if (copy_to_user(ep_user, &edata, sizeof(edata)))
return -EFAULT;
if (copy_to_user(ep_user + sizeof(edata),
&ethtool_cassini_statnames,
(edata.len * ETH_GSTRING_LEN)))
return -EFAULT;
return 0;
default:
return -EINVAL;
}
}
case ETHTOOL_GSTATS: {
int i = 0; int i = 0;
u64 *tmp; data[i++] = stats->collisions;
struct ethtool_stats edata; data[i++] = stats->rx_bytes;
struct net_device_stats *stats; data[i++] = stats->rx_crc_errors;
int len; data[i++] = stats->rx_dropped;
data[i++] = stats->rx_errors;
if (copy_from_user(&edata, ep_user, sizeof(edata))) data[i++] = stats->rx_fifo_errors;
return -EFAULT; data[i++] = stats->rx_frame_errors;
data[i++] = stats->rx_length_errors;
len = edata.n_stats; data[i++] = stats->rx_over_errors;
stats = cas_get_stats(cp->dev); data[i++] = stats->rx_packets;
edata.cmd = ETHTOOL_GSTATS; data[i++] = stats->tx_aborted_errors;
edata.n_stats = (len < CAS_NUM_STAT_KEYS) ? data[i++] = stats->tx_bytes;
len : CAS_NUM_STAT_KEYS; data[i++] = stats->tx_dropped;
if (copy_to_user(ep_user, &edata, sizeof (edata))) data[i++] = stats->tx_errors;
return -EFAULT; data[i++] = stats->tx_fifo_errors;
data[i++] = stats->tx_packets;
tmp = kmalloc(sizeof(u64)*CAS_NUM_STAT_KEYS, GFP_KERNEL);
if (tmp) {
tmp[i++] = stats->collisions;
tmp[i++] = stats->rx_bytes;
tmp[i++] = stats->rx_crc_errors;
tmp[i++] = stats->rx_dropped;
tmp[i++] = stats->rx_errors;
tmp[i++] = stats->rx_fifo_errors;
tmp[i++] = stats->rx_frame_errors;
tmp[i++] = stats->rx_length_errors;
tmp[i++] = stats->rx_over_errors;
tmp[i++] = stats->rx_packets;
tmp[i++] = stats->tx_aborted_errors;
tmp[i++] = stats->tx_bytes;
tmp[i++] = stats->tx_dropped;
tmp[i++] = stats->tx_errors;
tmp[i++] = stats->tx_fifo_errors;
tmp[i++] = stats->tx_packets;
BUG_ON(i != CAS_NUM_STAT_KEYS); BUG_ON(i != CAS_NUM_STAT_KEYS);
i = copy_to_user(ep_user + sizeof(edata),
tmp, sizeof(u64)*edata.n_stats);
kfree(tmp);
} else {
return -ENOMEM;
}
if (i)
return -EFAULT;
return 0;
}
}
return -EOPNOTSUPP;
} }
static struct ethtool_ops cas_ethtool_ops = {
.get_drvinfo = cas_get_drvinfo,
.get_settings = cas_get_settings,
.set_settings = cas_set_settings,
.nway_reset = cas_nway_reset,
.get_link = cas_get_link,
.get_msglevel = cas_get_msglevel,
.set_msglevel = cas_set_msglevel,
.get_regs_len = cas_get_regs_len,
.get_regs = cas_get_regs,
.get_stats_count = cas_get_stats_count,
.get_strings = cas_get_strings,
.get_ethtool_stats = cas_get_ethtool_stats,
};
static int cas_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) static int cas_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{ {
struct cas *cp = netdev_priv(dev); struct cas *cp = netdev_priv(dev);
...@@ -4883,10 +4812,6 @@ static int cas_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -4883,10 +4812,6 @@ static int cas_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
*/ */
down(&cp->pm_sem); down(&cp->pm_sem);
switch (cmd) { switch (cmd) {
case SIOCETHTOOL:
rc = cas_ethtool_ioctl(dev, ifr->ifr_data);
break;
case SIOCGMIIPHY: /* Get address of MII PHY in use. */ case SIOCGMIIPHY: /* Get address of MII PHY in use. */
data->phy_id = cp->phy_addr; data->phy_id = cp->phy_addr;
/* Fallthrough... */ /* Fallthrough... */
...@@ -5112,6 +5037,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev, ...@@ -5112,6 +5037,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
dev->get_stats = cas_get_stats; dev->get_stats = cas_get_stats;
dev->set_multicast_list = cas_set_multicast; dev->set_multicast_list = cas_set_multicast;
dev->do_ioctl = cas_ioctl; dev->do_ioctl = cas_ioctl;
dev->ethtool_ops = &cas_ethtool_ops;
dev->tx_timeout = cas_tx_timeout; dev->tx_timeout = cas_tx_timeout;
dev->watchdog_timeo = CAS_TX_TIMEOUT; dev->watchdog_timeo = CAS_TX_TIMEOUT;
dev->change_mtu = cas_change_mtu; dev->change_mtu = cas_change_mtu;
......
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