aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/cassini.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/cassini.c')
-rw-r--r--drivers/net/cassini.c502
1 files changed, 214 insertions, 288 deletions
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index 45831fb377a0..2e617424d3fb 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -4423,18 +4423,14 @@ static struct {
4423#define CAS_REG_LEN (sizeof(ethtool_register_table)/sizeof(int)) 4423#define CAS_REG_LEN (sizeof(ethtool_register_table)/sizeof(int))
4424#define CAS_MAX_REGS (sizeof (u32)*CAS_REG_LEN) 4424#define CAS_MAX_REGS (sizeof (u32)*CAS_REG_LEN)
4425 4425
4426static u8 *cas_get_regs(struct cas *cp) 4426static void cas_read_regs(struct cas *cp, u8 *ptr, int len)
4427{ 4427{
4428 u8 *ptr = kmalloc(CAS_MAX_REGS, GFP_KERNEL);
4429 u8 *p; 4428 u8 *p;
4430 int i; 4429 int i;
4431 unsigned long flags; 4430 unsigned long flags;
4432 4431
4433 if (!ptr)
4434 return NULL;
4435
4436 spin_lock_irqsave(&cp->lock, flags); 4432 spin_lock_irqsave(&cp->lock, flags);
4437 for (i = 0, p = ptr; i < CAS_REG_LEN ; i ++, p += sizeof(u32)) { 4433 for (i = 0, p = ptr; i < len ; i ++, p += sizeof(u32)) {
4438 u16 hval; 4434 u16 hval;
4439 u32 val; 4435 u32 val;
4440 if (ethtool_register_table[i].offsets < 0) { 4436 if (ethtool_register_table[i].offsets < 0) {
@@ -4447,8 +4443,6 @@ static u8 *cas_get_regs(struct cas *cp)
4447 memcpy(p, (u8 *)&val, sizeof(u32)); 4443 memcpy(p, (u8 *)&val, sizeof(u32));
4448 } 4444 }
4449 spin_unlock_irqrestore(&cp->lock, flags); 4445 spin_unlock_irqrestore(&cp->lock, flags);
4450
4451 return ptr;
4452} 4446}
4453 4447
4454static struct net_device_stats *cas_get_stats(struct net_device *dev) 4448static struct net_device_stats *cas_get_stats(struct net_device *dev)
@@ -4561,316 +4555,251 @@ static void cas_set_multicast(struct net_device *dev)
4561 spin_unlock_irqrestore(&cp->lock, flags); 4555 spin_unlock_irqrestore(&cp->lock, flags);
4562} 4556}
4563 4557
4564/* Eventually add support for changing the advertisement 4558static void cas_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
4565 * on autoneg. 4559{
4566 */ 4560 struct cas *cp = netdev_priv(dev);
4567static int cas_ethtool_ioctl(struct net_device *dev, void __user *ep_user) 4561 strncpy(info->driver, DRV_MODULE_NAME, ETHTOOL_BUSINFO_LEN);
4562 strncpy(info->version, DRV_MODULE_VERSION, ETHTOOL_BUSINFO_LEN);
4563 info->fw_version[0] = '\0';
4564 strncpy(info->bus_info, pci_name(cp->pdev), ETHTOOL_BUSINFO_LEN);
4565 info->regdump_len = cp->casreg_len < CAS_MAX_REGS ?
4566 cp->casreg_len : CAS_MAX_REGS;
4567 info->n_stats = CAS_NUM_STAT_KEYS;
4568}
4569
4570static int cas_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
4568{ 4571{
4569 struct cas *cp = netdev_priv(dev); 4572 struct cas *cp = netdev_priv(dev);
4570 u16 bmcr; 4573 u16 bmcr;
4571 int full_duplex, speed, pause; 4574 int full_duplex, speed, pause;
4572 struct ethtool_cmd ecmd;
4573 unsigned long flags; 4575 unsigned long flags;
4574 enum link_state linkstate = link_up; 4576 enum link_state linkstate = link_up;
4575 4577
4576 if (copy_from_user(&ecmd, ep_user, sizeof(ecmd))) 4578 cmd->advertising = 0;
4577 return -EFAULT; 4579 cmd->supported = SUPPORTED_Autoneg;
4578 4580 if (cp->cas_flags & CAS_FLAG_1000MB_CAP) {
4579 switch(ecmd.cmd) { 4581 cmd->supported |= SUPPORTED_1000baseT_Full;
4580 case ETHTOOL_GDRVINFO: { 4582 cmd->advertising |= ADVERTISED_1000baseT_Full;
4581 struct ethtool_drvinfo info = { .cmd = ETHTOOL_GDRVINFO };
4582
4583 strncpy(info.driver, DRV_MODULE_NAME,
4584 ETHTOOL_BUSINFO_LEN);
4585 strncpy(info.version, DRV_MODULE_VERSION,
4586 ETHTOOL_BUSINFO_LEN);
4587 info.fw_version[0] = '\0';
4588 strncpy(info.bus_info, pci_name(cp->pdev),
4589 ETHTOOL_BUSINFO_LEN);
4590 info.regdump_len = cp->casreg_len < CAS_MAX_REGS ?
4591 cp->casreg_len : CAS_MAX_REGS;
4592 info.n_stats = CAS_NUM_STAT_KEYS;
4593 if (copy_to_user(ep_user, &info, sizeof(info)))
4594 return -EFAULT;
4595
4596 return 0;
4597 } 4583 }
4598 4584
4599 case ETHTOOL_GSET: 4585 /* Record PHY settings if HW is on. */
4600 ecmd.advertising = 0; 4586 spin_lock_irqsave(&cp->lock, flags);
4601 ecmd.supported = SUPPORTED_Autoneg; 4587 bmcr = 0;
4602 if (cp->cas_flags & CAS_FLAG_1000MB_CAP) { 4588 linkstate = cp->lstate;
4603 ecmd.supported |= SUPPORTED_1000baseT_Full; 4589 if (CAS_PHY_MII(cp->phy_type)) {
4604 ecmd.advertising |= ADVERTISED_1000baseT_Full; 4590 cmd->port = PORT_MII;
4591 cmd->transceiver = (cp->cas_flags & CAS_FLAG_SATURN) ?
4592 XCVR_INTERNAL : XCVR_EXTERNAL;
4593 cmd->phy_address = cp->phy_addr;
4594 cmd->advertising |= ADVERTISED_TP | ADVERTISED_MII |
4595 ADVERTISED_10baseT_Half |
4596 ADVERTISED_10baseT_Full |
4597 ADVERTISED_100baseT_Half |
4598 ADVERTISED_100baseT_Full;
4599
4600 cmd->supported |=
4601 (SUPPORTED_10baseT_Half |
4602 SUPPORTED_10baseT_Full |
4603 SUPPORTED_100baseT_Half |
4604 SUPPORTED_100baseT_Full |
4605 SUPPORTED_TP | SUPPORTED_MII);
4606
4607 if (cp->hw_running) {
4608 cas_mif_poll(cp, 0);
4609 bmcr = cas_phy_read(cp, MII_BMCR);
4610 cas_read_mii_link_mode(cp, &full_duplex,
4611 &speed, &pause);
4612 cas_mif_poll(cp, 1);
4605 } 4613 }
4606 4614
4607 /* Record PHY settings if HW is on. */ 4615 } else {
4608 spin_lock_irqsave(&cp->lock, flags); 4616 cmd->port = PORT_FIBRE;
4609 bmcr = 0; 4617 cmd->transceiver = XCVR_INTERNAL;
4610 linkstate = cp->lstate; 4618 cmd->phy_address = 0;
4611 if (CAS_PHY_MII(cp->phy_type)) { 4619 cmd->supported |= SUPPORTED_FIBRE;
4612 ecmd.port = PORT_MII; 4620 cmd->advertising |= ADVERTISED_FIBRE;
4613 ecmd.transceiver = (cp->cas_flags & CAS_FLAG_SATURN) ? 4621
4614 XCVR_INTERNAL : XCVR_EXTERNAL; 4622 if (cp->hw_running) {
4615 ecmd.phy_address = cp->phy_addr; 4623 /* pcs uses the same bits as mii */
4616 ecmd.advertising |= ADVERTISED_TP | ADVERTISED_MII | 4624 bmcr = readl(cp->regs + REG_PCS_MII_CTRL);
4617 ADVERTISED_10baseT_Half | 4625 cas_read_pcs_link_mode(cp, &full_duplex,
4618 ADVERTISED_10baseT_Full | 4626 &speed, &pause);
4619 ADVERTISED_100baseT_Half |
4620 ADVERTISED_100baseT_Full;
4621
4622 ecmd.supported |=
4623 (SUPPORTED_10baseT_Half |
4624 SUPPORTED_10baseT_Full |
4625 SUPPORTED_100baseT_Half |
4626 SUPPORTED_100baseT_Full |
4627 SUPPORTED_TP | SUPPORTED_MII);
4628
4629 if (cp->hw_running) {
4630 cas_mif_poll(cp, 0);
4631 bmcr = cas_phy_read(cp, MII_BMCR);
4632 cas_read_mii_link_mode(cp, &full_duplex,
4633 &speed, &pause);
4634 cas_mif_poll(cp, 1);
4635 }
4636
4637 } else {
4638 ecmd.port = PORT_FIBRE;
4639 ecmd.transceiver = XCVR_INTERNAL;
4640 ecmd.phy_address = 0;
4641 ecmd.supported |= SUPPORTED_FIBRE;
4642 ecmd.advertising |= ADVERTISED_FIBRE;
4643
4644 if (cp->hw_running) {
4645 /* pcs uses the same bits as mii */
4646 bmcr = readl(cp->regs + REG_PCS_MII_CTRL);
4647 cas_read_pcs_link_mode(cp, &full_duplex,
4648 &speed, &pause);
4649 }
4650 } 4627 }
4651 spin_unlock_irqrestore(&cp->lock, flags); 4628 }
4629 spin_unlock_irqrestore(&cp->lock, flags);
4652 4630
4653 if (bmcr & BMCR_ANENABLE) { 4631 if (bmcr & BMCR_ANENABLE) {
4654 ecmd.advertising |= ADVERTISED_Autoneg; 4632 cmd->advertising |= ADVERTISED_Autoneg;
4655 ecmd.autoneg = AUTONEG_ENABLE; 4633 cmd->autoneg = AUTONEG_ENABLE;
4656 ecmd.speed = ((speed == 10) ? 4634 cmd->speed = ((speed == 10) ?
4657 SPEED_10 : 4635 SPEED_10 :
4658 ((speed == 1000) ? 4636 ((speed == 1000) ?
4659 SPEED_1000 : SPEED_100)); 4637 SPEED_1000 : SPEED_100));
4660 ecmd.duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF; 4638 cmd->duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
4639 } else {
4640 cmd->autoneg = AUTONEG_DISABLE;
4641 cmd->speed =
4642 (bmcr & CAS_BMCR_SPEED1000) ?
4643 SPEED_1000 :
4644 ((bmcr & BMCR_SPEED100) ? SPEED_100:
4645 SPEED_10);
4646 cmd->duplex =
4647 (bmcr & BMCR_FULLDPLX) ?
4648 DUPLEX_FULL : DUPLEX_HALF;
4649 }
4650 if (linkstate != link_up) {
4651 /* Force these to "unknown" if the link is not up and
4652 * autonogotiation in enabled. We can set the link
4653 * speed to 0, but not cmd->duplex,
4654 * because its legal values are 0 and 1. Ethtool will
4655 * print the value reported in parentheses after the
4656 * word "Unknown" for unrecognized values.
4657 *
4658 * If in forced mode, we report the speed and duplex
4659 * settings that we configured.
4660 */
4661 if (cp->link_cntl & BMCR_ANENABLE) {
4662 cmd->speed = 0;
4663 cmd->duplex = 0xff;
4661 } else { 4664 } else {
4662 ecmd.autoneg = AUTONEG_DISABLE; 4665 cmd->speed = SPEED_10;
4663 ecmd.speed = 4666 if (cp->link_cntl & BMCR_SPEED100) {
4664 (bmcr & CAS_BMCR_SPEED1000) ? 4667 cmd->speed = SPEED_100;
4665 SPEED_1000 : 4668 } else if (cp->link_cntl & CAS_BMCR_SPEED1000) {
4666 ((bmcr & BMCR_SPEED100) ? SPEED_100: 4669 cmd->speed = SPEED_1000;
4667 SPEED_10);
4668 ecmd.duplex =
4669 (bmcr & BMCR_FULLDPLX) ?
4670 DUPLEX_FULL : DUPLEX_HALF;
4671 }
4672 if (linkstate != link_up) {
4673 /* Force these to "unknown" if the link is not up and
4674 * autonogotiation in enabled. We can set the link
4675 * speed to 0, but not ecmd.duplex,
4676 * because its legal values are 0 and 1. Ethtool will
4677 * print the value reported in parentheses after the
4678 * word "Unknown" for unrecognized values.
4679 *
4680 * If in forced mode, we report the speed and duplex
4681 * settings that we configured.
4682 */
4683 if (cp->link_cntl & BMCR_ANENABLE) {
4684 ecmd.speed = 0;
4685 ecmd.duplex = 0xff;
4686 } else {
4687 ecmd.speed = SPEED_10;
4688 if (cp->link_cntl & BMCR_SPEED100) {
4689 ecmd.speed = SPEED_100;
4690 } else if (cp->link_cntl & CAS_BMCR_SPEED1000) {
4691 ecmd.speed = SPEED_1000;
4692 }
4693 ecmd.duplex = (cp->link_cntl & BMCR_FULLDPLX)?
4694 DUPLEX_FULL : DUPLEX_HALF;
4695 } 4670 }
4671 cmd->duplex = (cp->link_cntl & BMCR_FULLDPLX)?
4672 DUPLEX_FULL : DUPLEX_HALF;
4696 } 4673 }
4697 if (copy_to_user(ep_user, &ecmd, sizeof(ecmd))) 4674 }
4698 return -EFAULT; 4675 return 0;
4699 return 0; 4676}
4700 4677
4701 case ETHTOOL_SSET: 4678static int cas_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
4702 if (!capable(CAP_NET_ADMIN)) 4679{
4703 return -EPERM; 4680 struct cas *cp = netdev_priv(dev);
4681 unsigned long flags;
4704 4682
4705 /* Verify the settings we care about. */ 4683 /* Verify the settings we care about. */
4706 if (ecmd.autoneg != AUTONEG_ENABLE && 4684 if (cmd->autoneg != AUTONEG_ENABLE &&
4707 ecmd.autoneg != AUTONEG_DISABLE) 4685 cmd->autoneg != AUTONEG_DISABLE)
4708 return -EINVAL; 4686 return -EINVAL;
4709 4687
4710 if (ecmd.autoneg == AUTONEG_DISABLE && 4688 if (cmd->autoneg == AUTONEG_DISABLE &&
4711 ((ecmd.speed != SPEED_1000 && 4689 ((cmd->speed != SPEED_1000 &&
4712 ecmd.speed != SPEED_100 && 4690 cmd->speed != SPEED_100 &&
4713 ecmd.speed != SPEED_10) || 4691 cmd->speed != SPEED_10) ||
4714 (ecmd.duplex != DUPLEX_HALF && 4692 (cmd->duplex != DUPLEX_HALF &&
4715 ecmd.duplex != DUPLEX_FULL))) 4693 cmd->duplex != DUPLEX_FULL)))
4716 return -EINVAL; 4694 return -EINVAL;
4717 4695
4718 /* Apply settings and restart link process. */ 4696 /* Apply settings and restart link process. */
4719 spin_lock_irqsave(&cp->lock, flags); 4697 spin_lock_irqsave(&cp->lock, flags);
4720 cas_begin_auto_negotiation(cp, &ecmd); 4698 cas_begin_auto_negotiation(cp, cmd);
4721 spin_unlock_irqrestore(&cp->lock, flags); 4699 spin_unlock_irqrestore(&cp->lock, flags);
4722 return 0; 4700 return 0;
4701}
4723 4702
4724 case ETHTOOL_NWAY_RST: 4703static int cas_nway_reset(struct net_device *dev)
4725 if ((cp->link_cntl & BMCR_ANENABLE) == 0) 4704{
4726 return -EINVAL; 4705 struct cas *cp = netdev_priv(dev);
4706 unsigned long flags;
4727 4707
4728 /* Restart link process. */ 4708 if ((cp->link_cntl & BMCR_ANENABLE) == 0)
4729 spin_lock_irqsave(&cp->lock, flags); 4709 return -EINVAL;
4730 cas_begin_auto_negotiation(cp, NULL);
4731 spin_unlock_irqrestore(&cp->lock, flags);
4732 4710
4733 return 0; 4711 /* Restart link process. */
4712 spin_lock_irqsave(&cp->lock, flags);
4713 cas_begin_auto_negotiation(cp, NULL);
4714 spin_unlock_irqrestore(&cp->lock, flags);
4734 4715
4735 case ETHTOOL_GWOL: 4716 return 0;
4736 case ETHTOOL_SWOL: 4717}
4737 break; /* doesn't exist */
4738 4718
4739 /* get link status */ 4719static u32 cas_get_link(struct net_device *dev)
4740 case ETHTOOL_GLINK: { 4720{
4741 struct ethtool_value edata = { .cmd = ETHTOOL_GLINK }; 4721 struct cas *cp = netdev_priv(dev);
4722 return cp->lstate == link_up;
4723}
4742 4724
4743 edata.data = (cp->lstate == link_up); 4725static u32 cas_get_msglevel(struct net_device *dev)
4744 if (copy_to_user(ep_user, &edata, sizeof(edata))) 4726{
4745 return -EFAULT; 4727 struct cas *cp = netdev_priv(dev);
4746 return 0; 4728 return cp->msg_enable;
4747 } 4729}
4748 4730
4749 /* get message-level */ 4731static void cas_set_msglevel(struct net_device *dev, u32 value)
4750 case ETHTOOL_GMSGLVL: { 4732{
4751 struct ethtool_value edata = { .cmd = ETHTOOL_GMSGLVL }; 4733 struct cas *cp = netdev_priv(dev);
4734 cp->msg_enable = value;
4735}
4752 4736
4753 edata.data = cp->msg_enable; 4737static int cas_get_regs_len(struct net_device *dev)
4754 if (copy_to_user(ep_user, &edata, sizeof(edata))) 4738{
4755 return -EFAULT; 4739 struct cas *cp = netdev_priv(dev);
4756 return 0; 4740 return cp->casreg_len < CAS_MAX_REGS ? cp->casreg_len: CAS_MAX_REGS;
4757 } 4741}
4758 4742
4759 /* set message-level */ 4743static void cas_get_regs(struct net_device *dev, struct ethtool_regs *regs,
4760 case ETHTOOL_SMSGLVL: { 4744 void *p)
4761 struct ethtool_value edata; 4745{
4746 struct cas *cp = netdev_priv(dev);
4747 regs->version = 0;
4748 /* cas_read_regs handles locks (cp->lock). */
4749 cas_read_regs(cp, p, regs->len / sizeof(u32));
4750}
4762 4751
4763 if (!capable(CAP_NET_ADMIN)) { 4752static int cas_get_stats_count(struct net_device *dev)
4764 return (-EPERM); 4753{
4765 } 4754 return CAS_NUM_STAT_KEYS;
4766 if (copy_from_user(&edata, ep_user, sizeof(edata))) 4755}
4767 return -EFAULT;
4768 cp->msg_enable = edata.data;
4769 return 0;
4770 }
4771 4756
4772 case ETHTOOL_GREGS: { 4757static void cas_get_strings(struct net_device *dev, u32 stringset, u8 *data)
4773 struct ethtool_regs edata; 4758{
4774 u8 *ptr; 4759 memcpy(data, &ethtool_cassini_statnames,
4775 int len = cp->casreg_len < CAS_MAX_REGS ? 4760 CAS_NUM_STAT_KEYS * ETH_GSTRING_LEN);
4776 cp->casreg_len: CAS_MAX_REGS; 4761}
4777
4778 if (copy_from_user(&edata, ep_user, sizeof (edata)))
4779 return -EFAULT;
4780
4781 if (edata.len > len)
4782 edata.len = len;
4783 edata.version = 0;
4784 if (copy_to_user (ep_user, &edata, sizeof(edata)))
4785 return -EFAULT;
4786
4787 /* cas_get_regs handles locks (cp->lock). */
4788 ptr = cas_get_regs(cp);
4789 if (ptr == NULL)
4790 return -ENOMEM;
4791 if (copy_to_user(ep_user + sizeof (edata), ptr, edata.len))
4792 return -EFAULT;
4793
4794 kfree(ptr);
4795 return (0);
4796 }
4797 case ETHTOOL_GSTRINGS: {
4798 struct ethtool_gstrings edata;
4799 int len;
4800
4801 if (copy_from_user(&edata, ep_user, sizeof(edata)))
4802 return -EFAULT;
4803
4804 len = edata.len;
4805 switch(edata.string_set) {
4806 case ETH_SS_STATS:
4807 edata.len = (len < CAS_NUM_STAT_KEYS) ?
4808 len : CAS_NUM_STAT_KEYS;
4809 if (copy_to_user(ep_user, &edata, sizeof(edata)))
4810 return -EFAULT;
4811
4812 if (copy_to_user(ep_user + sizeof(edata),
4813 &ethtool_cassini_statnames,
4814 (edata.len * ETH_GSTRING_LEN)))
4815 return -EFAULT;
4816 return 0;
4817 default:
4818 return -EINVAL;
4819 }
4820 }
4821 case ETHTOOL_GSTATS: {
4822 int i = 0;
4823 u64 *tmp;
4824 struct ethtool_stats edata;
4825 struct net_device_stats *stats;
4826 int len;
4827
4828 if (copy_from_user(&edata, ep_user, sizeof(edata)))
4829 return -EFAULT;
4830
4831 len = edata.n_stats;
4832 stats = cas_get_stats(cp->dev);
4833 edata.cmd = ETHTOOL_GSTATS;
4834 edata.n_stats = (len < CAS_NUM_STAT_KEYS) ?
4835 len : CAS_NUM_STAT_KEYS;
4836 if (copy_to_user(ep_user, &edata, sizeof (edata)))
4837 return -EFAULT;
4838
4839 tmp = kmalloc(sizeof(u64)*CAS_NUM_STAT_KEYS, GFP_KERNEL);
4840 if (tmp) {
4841 tmp[i++] = stats->collisions;
4842 tmp[i++] = stats->rx_bytes;
4843 tmp[i++] = stats->rx_crc_errors;
4844 tmp[i++] = stats->rx_dropped;
4845 tmp[i++] = stats->rx_errors;
4846 tmp[i++] = stats->rx_fifo_errors;
4847 tmp[i++] = stats->rx_frame_errors;
4848 tmp[i++] = stats->rx_length_errors;
4849 tmp[i++] = stats->rx_over_errors;
4850 tmp[i++] = stats->rx_packets;
4851 tmp[i++] = stats->tx_aborted_errors;
4852 tmp[i++] = stats->tx_bytes;
4853 tmp[i++] = stats->tx_dropped;
4854 tmp[i++] = stats->tx_errors;
4855 tmp[i++] = stats->tx_fifo_errors;
4856 tmp[i++] = stats->tx_packets;
4857 BUG_ON(i != CAS_NUM_STAT_KEYS);
4858
4859 i = copy_to_user(ep_user + sizeof(edata),
4860 tmp, sizeof(u64)*edata.n_stats);
4861 kfree(tmp);
4862 } else {
4863 return -ENOMEM;
4864 }
4865 if (i)
4866 return -EFAULT;
4867 return 0;
4868 }
4869 }
4870 4762
4871 return -EOPNOTSUPP; 4763static void cas_get_ethtool_stats(struct net_device *dev,
4764 struct ethtool_stats *estats, u64 *data)
4765{
4766 struct cas *cp = netdev_priv(dev);
4767 struct net_device_stats *stats = cas_get_stats(cp->dev);
4768 int i = 0;
4769 data[i++] = stats->collisions;
4770 data[i++] = stats->rx_bytes;
4771 data[i++] = stats->rx_crc_errors;
4772 data[i++] = stats->rx_dropped;
4773 data[i++] = stats->rx_errors;
4774 data[i++] = stats->rx_fifo_errors;
4775 data[i++] = stats->rx_frame_errors;
4776 data[i++] = stats->rx_length_errors;
4777 data[i++] = stats->rx_over_errors;
4778 data[i++] = stats->rx_packets;
4779 data[i++] = stats->tx_aborted_errors;
4780 data[i++] = stats->tx_bytes;
4781 data[i++] = stats->tx_dropped;
4782 data[i++] = stats->tx_errors;
4783 data[i++] = stats->tx_fifo_errors;
4784 data[i++] = stats->tx_packets;
4785 BUG_ON(i != CAS_NUM_STAT_KEYS);
4872} 4786}
4873 4787
4788static struct ethtool_ops cas_ethtool_ops = {
4789 .get_drvinfo = cas_get_drvinfo,
4790 .get_settings = cas_get_settings,
4791 .set_settings = cas_set_settings,
4792 .nway_reset = cas_nway_reset,
4793 .get_link = cas_get_link,
4794 .get_msglevel = cas_get_msglevel,
4795 .set_msglevel = cas_set_msglevel,
4796 .get_regs_len = cas_get_regs_len,
4797 .get_regs = cas_get_regs,
4798 .get_stats_count = cas_get_stats_count,
4799 .get_strings = cas_get_strings,
4800 .get_ethtool_stats = cas_get_ethtool_stats,
4801};
4802
4874static int cas_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 4803static int cas_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
4875{ 4804{
4876 struct cas *cp = netdev_priv(dev); 4805 struct cas *cp = netdev_priv(dev);
@@ -4883,10 +4812,6 @@ static int cas_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
4883 */ 4812 */
4884 down(&cp->pm_sem); 4813 down(&cp->pm_sem);
4885 switch (cmd) { 4814 switch (cmd) {
4886 case SIOCETHTOOL:
4887 rc = cas_ethtool_ioctl(dev, ifr->ifr_data);
4888 break;
4889
4890 case SIOCGMIIPHY: /* Get address of MII PHY in use. */ 4815 case SIOCGMIIPHY: /* Get address of MII PHY in use. */
4891 data->phy_id = cp->phy_addr; 4816 data->phy_id = cp->phy_addr;
4892 /* Fallthrough... */ 4817 /* Fallthrough... */
@@ -5112,6 +5037,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
5112 dev->get_stats = cas_get_stats; 5037 dev->get_stats = cas_get_stats;
5113 dev->set_multicast_list = cas_set_multicast; 5038 dev->set_multicast_list = cas_set_multicast;
5114 dev->do_ioctl = cas_ioctl; 5039 dev->do_ioctl = cas_ioctl;
5040 dev->ethtool_ops = &cas_ethtool_ops;
5115 dev->tx_timeout = cas_tx_timeout; 5041 dev->tx_timeout = cas_tx_timeout;
5116 dev->watchdog_timeo = CAS_TX_TIMEOUT; 5042 dev->watchdog_timeo = CAS_TX_TIMEOUT;
5117 dev->change_mtu = cas_change_mtu; 5043 dev->change_mtu = cas_change_mtu;