diff options
Diffstat (limited to 'drivers/net/forcedeth.c')
-rw-r--r-- | drivers/net/forcedeth.c | 113 |
1 files changed, 41 insertions, 72 deletions
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index d5ab4da..d09e8b0 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -774,7 +774,6 @@ struct fe_priv { u32 driver_data; u32 device_id; u32 register_size; - int rx_csum; u32 mac_in_use; int mgmt_version; int mgmt_sema; @@ -3956,6 +3955,7 @@ static int nv_set_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo) static int nv_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { struct fe_priv *np = netdev_priv(dev); + u32 speed; int adv; spin_lock_irq(&np->lock); @@ -3975,23 +3975,26 @@ static int nv_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) if (netif_carrier_ok(dev)) { switch (np->linkspeed & (NVREG_LINKSPEED_MASK)) { case NVREG_LINKSPEED_10: - ecmd->speed = SPEED_10; + speed = SPEED_10; break; case NVREG_LINKSPEED_100: - ecmd->speed = SPEED_100; + speed = SPEED_100; break; case NVREG_LINKSPEED_1000: - ecmd->speed = SPEED_1000; + speed = SPEED_1000; + break; + default: + speed = -1; break; } ecmd->duplex = DUPLEX_HALF; if (np->duplex) ecmd->duplex = DUPLEX_FULL; } else { - ecmd->speed = -1; + speed = -1; ecmd->duplex = -1; } - + ethtool_cmd_speed_set(ecmd, speed); ecmd->autoneg = np->autoneg; ecmd->advertising = ADVERTISED_MII; @@ -4030,6 +4033,7 @@ static int nv_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { struct fe_priv *np = netdev_priv(dev); + u32 speed = ethtool_cmd_speed(ecmd); if (ecmd->port != PORT_MII) return -EINVAL; @@ -4055,7 +4059,7 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) /* Note: autonegotiation disable, speed 1000 intentionally * forbidden - no one should need that. */ - if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100) + if (speed != SPEED_10 && speed != SPEED_100) return -EINVAL; if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) return -EINVAL; @@ -4139,13 +4143,13 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); - if (ecmd->speed == SPEED_10 && ecmd->duplex == DUPLEX_HALF) + if (speed == SPEED_10 && ecmd->duplex == DUPLEX_HALF) adv |= ADVERTISE_10HALF; - if (ecmd->speed == SPEED_10 && ecmd->duplex == DUPLEX_FULL) + if (speed == SPEED_10 && ecmd->duplex == DUPLEX_FULL) adv |= ADVERTISE_10FULL; - if (ecmd->speed == SPEED_100 && ecmd->duplex == DUPLEX_HALF) + if (speed == SPEED_100 && ecmd->duplex == DUPLEX_HALF) adv |= ADVERTISE_100HALF; - if (ecmd->speed == SPEED_100 && ecmd->duplex == DUPLEX_FULL) + if (speed == SPEED_100 && ecmd->duplex == DUPLEX_FULL) adv |= ADVERTISE_100FULL; np->pause_flags &= ~(NV_PAUSEFRAME_AUTONEG|NV_PAUSEFRAME_RX_ENABLE|NV_PAUSEFRAME_TX_ENABLE); if (np->pause_flags & NV_PAUSEFRAME_RX_REQ) {/* for rx we set both advertisements but disable tx pause */ @@ -4264,16 +4268,6 @@ static int nv_nway_reset(struct net_device *dev) return ret; } -static int nv_set_tso(struct net_device *dev, u32 value) -{ - struct fe_priv *np = netdev_priv(dev); - - if ((np->driver_data & DEV_HAS_CHECKSUM)) - return ethtool_op_set_tso(dev, value); - else - return -EOPNOTSUPP; -} - static void nv_get_ringparam(struct net_device *dev, struct ethtool_ringparam* ring) { struct fe_priv *np = netdev_priv(dev); @@ -4480,58 +4474,36 @@ static int nv_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam* return 0; } -static u32 nv_get_rx_csum(struct net_device *dev) +static u32 nv_fix_features(struct net_device *dev, u32 features) { - struct fe_priv *np = netdev_priv(dev); - return np->rx_csum != 0; + /* vlan is dependent on rx checksum offload */ + if (features & (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX)) + features |= NETIF_F_RXCSUM; + + return features; } -static int nv_set_rx_csum(struct net_device *dev, u32 data) +static int nv_set_features(struct net_device *dev, u32 features) { struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); - int retcode = 0; - - if (np->driver_data & DEV_HAS_CHECKSUM) { - if (data) { - np->rx_csum = 1; - np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK; - } else { - np->rx_csum = 0; - /* vlan is dependent on rx checksum offload */ - if (!(np->vlanctl_bits & NVREG_VLANCONTROL_ENABLE)) - np->txrxctl_bits &= ~NVREG_TXRXCTL_RXCHECK; - } - if (netif_running(dev)) { - spin_lock_irq(&np->lock); - writel(np->txrxctl_bits, base + NvRegTxRxControl); - spin_unlock_irq(&np->lock); - } - } else { - return -EINVAL; - } + u32 changed = dev->features ^ features; - return retcode; -} + if (changed & NETIF_F_RXCSUM) { + spin_lock_irq(&np->lock); -static int nv_set_tx_csum(struct net_device *dev, u32 data) -{ - struct fe_priv *np = netdev_priv(dev); + if (features & NETIF_F_RXCSUM) + np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK; + else + np->txrxctl_bits &= ~NVREG_TXRXCTL_RXCHECK; - if (np->driver_data & DEV_HAS_CHECKSUM) - return ethtool_op_set_tx_csum(dev, data); - else - return -EOPNOTSUPP; -} + if (netif_running(dev)) + writel(np->txrxctl_bits, base + NvRegTxRxControl); -static int nv_set_sg(struct net_device *dev, u32 data) -{ - struct fe_priv *np = netdev_priv(dev); + spin_unlock_irq(&np->lock); + } - if (np->driver_data & DEV_HAS_CHECKSUM) - return ethtool_op_set_sg(dev, data); - else - return -EOPNOTSUPP; + return 0; } static int nv_get_sset_count(struct net_device *dev, int sset) @@ -4896,15 +4868,10 @@ static const struct ethtool_ops ops = { .get_regs_len = nv_get_regs_len, .get_regs = nv_get_regs, .nway_reset = nv_nway_reset, - .set_tso = nv_set_tso, .get_ringparam = nv_get_ringparam, .set_ringparam = nv_set_ringparam, .get_pauseparam = nv_get_pauseparam, .set_pauseparam = nv_set_pauseparam, - .get_rx_csum = nv_get_rx_csum, - .set_rx_csum = nv_set_rx_csum, - .set_tx_csum = nv_set_tx_csum, - .set_sg = nv_set_sg, .get_strings = nv_get_strings, .get_ethtool_stats = nv_get_ethtool_stats, .get_sset_count = nv_get_sset_count, @@ -5235,6 +5202,8 @@ static const struct net_device_ops nv_netdev_ops = { .ndo_start_xmit = nv_start_xmit, .ndo_tx_timeout = nv_tx_timeout, .ndo_change_mtu = nv_change_mtu, + .ndo_fix_features = nv_fix_features, + .ndo_set_features = nv_set_features, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = nv_set_mac_address, .ndo_set_multicast_list = nv_set_multicast, @@ -5251,6 +5220,8 @@ static const struct net_device_ops nv_netdev_ops_optimized = { .ndo_start_xmit = nv_start_xmit_optimized, .ndo_tx_timeout = nv_tx_timeout, .ndo_change_mtu = nv_change_mtu, + .ndo_fix_features = nv_fix_features, + .ndo_set_features = nv_set_features, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = nv_set_mac_address, .ndo_set_multicast_list = nv_set_multicast, @@ -5364,11 +5335,10 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i np->pkt_limit = NV_PKTLIMIT_2; if (id->driver_data & DEV_HAS_CHECKSUM) { - np->rx_csum = 1; np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK; - dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; - dev->features |= NETIF_F_TSO; - dev->features |= NETIF_F_GRO; + dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_SG | + NETIF_F_TSO | NETIF_F_RXCSUM; + dev->features |= dev->hw_features; } np->vlanctl_bits = 0; @@ -5384,7 +5354,6 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i np->pause_flags |= NV_PAUSEFRAME_TX_CAPABLE | NV_PAUSEFRAME_TX_REQ; } - err = -ENOMEM; np->base = ioremap(addr, np->register_size); if (!np->base) |