Loading drivers/net/forcedeth.c +176 −59 Original line number Diff line number Diff line Loading @@ -519,6 +519,9 @@ typedef union _ring_type { #define NV_PAUSEFRAME_TX_CAPABLE 0x0002 #define NV_PAUSEFRAME_RX_ENABLE 0x0004 #define NV_PAUSEFRAME_TX_ENABLE 0x0008 #define NV_PAUSEFRAME_RX_REQ 0x0010 #define NV_PAUSEFRAME_TX_REQ 0x0020 #define NV_PAUSEFRAME_AUTONEG 0x0040 /* MSI/MSI-X defines */ #define NV_MSI_X_MAX_VECTORS 8 Loading Loading @@ -1868,16 +1871,16 @@ static void nv_set_multicast(struct net_device *dev) u8 __iomem *base = get_hwbase(dev); u32 addr[2]; u32 mask[2]; u32 pff; u32 pff = readl(base + NvRegPacketFilterFlags) & NVREG_PFF_PAUSE_RX; memset(addr, 0, sizeof(addr)); memset(mask, 0, sizeof(mask)); if (dev->flags & IFF_PROMISC) { printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); pff = NVREG_PFF_PROMISC; pff |= NVREG_PFF_PROMISC; } else { pff = NVREG_PFF_MYADDR; pff |= NVREG_PFF_MYADDR; if (dev->flags & IFF_ALLMULTI || dev->mc_list) { u32 alwaysOff[2]; Loading Loading @@ -1922,6 +1925,35 @@ static void nv_set_multicast(struct net_device *dev) spin_unlock_irq(&np->lock); } void nv_update_pause(struct net_device *dev, u32 pause_flags) { struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); np->pause_flags &= ~(NV_PAUSEFRAME_TX_ENABLE | NV_PAUSEFRAME_RX_ENABLE); if (np->pause_flags & NV_PAUSEFRAME_RX_CAPABLE) { u32 pff = readl(base + NvRegPacketFilterFlags) & ~NVREG_PFF_PAUSE_RX; if (pause_flags & NV_PAUSEFRAME_RX_ENABLE) { writel(pff|NVREG_PFF_PAUSE_RX, base + NvRegPacketFilterFlags); np->pause_flags |= NV_PAUSEFRAME_RX_ENABLE; } else { writel(pff, base + NvRegPacketFilterFlags); } } if (np->pause_flags & NV_PAUSEFRAME_TX_CAPABLE) { u32 regmisc = readl(base + NvRegMisc1) & ~NVREG_MISC1_PAUSE_TX; if (pause_flags & NV_PAUSEFRAME_TX_ENABLE) { writel(NVREG_TX_PAUSEFRAME_ENABLE, base + NvRegTxPauseFrame); writel(regmisc|NVREG_MISC1_PAUSE_TX, base + NvRegMisc1); np->pause_flags |= NV_PAUSEFRAME_TX_ENABLE; } else { writel(NVREG_TX_PAUSEFRAME_DISABLE, base + NvRegTxPauseFrame); writel(regmisc, base + NvRegMisc1); } } } /** * nv_update_linkspeed: Setup the MAC according to the link partner * @dev: Network device to be configured Loading @@ -1944,7 +1976,7 @@ static int nv_update_linkspeed(struct net_device *dev) int newdup = np->duplex; int mii_status; int retval = 0; u32 control_1000, status_1000, phyreg; u32 control_1000, status_1000, phyreg, pause_flags; /* BMSR_LSTATUS is latched, read it twice: * we want the current value. Loading Loading @@ -1990,6 +2022,11 @@ static int nv_update_linkspeed(struct net_device *dev) goto set_speed; } adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); lpa = mii_rw(dev, np->phyaddr, MII_LPA, MII_READ); dprintk(KERN_DEBUG "%s: nv_update_linkspeed: PHY advertises 0x%04x, lpa 0x%04x.\n", dev->name, adv, lpa); retval = 1; if (np->gigabit == PHY_GIGABIT) { control_1000 = mii_rw(dev, np->phyaddr, MII_CTRL1000, MII_READ); Loading @@ -2005,11 +2042,6 @@ static int nv_update_linkspeed(struct net_device *dev) } } adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); lpa = mii_rw(dev, np->phyaddr, MII_LPA, MII_READ); dprintk(KERN_DEBUG "%s: nv_update_linkspeed: PHY advertises 0x%04x, lpa 0x%04x.\n", dev->name, adv, lpa); /* FIXME: handle parallel detection properly */ adv_lpa = lpa & adv; if (adv_lpa & LPA_100FULL) { Loading Loading @@ -2068,55 +2100,45 @@ static int nv_update_linkspeed(struct net_device *dev) writel(np->linkspeed, base + NvRegLinkSpeed); pci_push(base); /* setup pause frame based on advertisement and link partner */ np->pause_flags &= ~(NV_PAUSEFRAME_TX_ENABLE | NV_PAUSEFRAME_RX_ENABLE); pause_flags = 0; /* setup pause frame */ if (np->duplex != 0) { if (np->autoneg && np->pause_flags & NV_PAUSEFRAME_AUTONEG) { adv_pause = adv & (ADVERTISE_PAUSE_CAP| ADVERTISE_PAUSE_ASYM); lpa_pause = lpa & (LPA_PAUSE_CAP| LPA_PAUSE_ASYM); switch (adv_pause) { case (ADVERTISE_PAUSE_CAP): if (lpa_pause & LPA_PAUSE_CAP) { np->pause_flags |= NV_PAUSEFRAME_TX_ENABLE | NV_PAUSEFRAME_RX_ENABLE; pause_flags |= NV_PAUSEFRAME_RX_ENABLE; if (np->pause_flags & NV_PAUSEFRAME_TX_REQ) pause_flags |= NV_PAUSEFRAME_TX_ENABLE; } break; case (ADVERTISE_PAUSE_ASYM): if (lpa_pause == (LPA_PAUSE_CAP| LPA_PAUSE_ASYM)) { np->pause_flags |= NV_PAUSEFRAME_TX_ENABLE; pause_flags |= NV_PAUSEFRAME_TX_ENABLE; } break; case (ADVERTISE_PAUSE_CAP| ADVERTISE_PAUSE_ASYM): if (lpa_pause & LPA_PAUSE_CAP) { np->pause_flags |= NV_PAUSEFRAME_TX_ENABLE | NV_PAUSEFRAME_RX_ENABLE; pause_flags |= NV_PAUSEFRAME_RX_ENABLE; if (np->pause_flags & NV_PAUSEFRAME_TX_REQ) pause_flags |= NV_PAUSEFRAME_TX_ENABLE; } if (lpa_pause == LPA_PAUSE_ASYM) { np->pause_flags |= NV_PAUSEFRAME_RX_ENABLE; pause_flags |= NV_PAUSEFRAME_RX_ENABLE; } break; } } if (np->pause_flags & NV_PAUSEFRAME_RX_CAPABLE) { u32 pff = readl(base + NvRegPacketFilterFlags) & ~NVREG_PFF_PAUSE_RX; if (np->pause_flags & NV_PAUSEFRAME_RX_ENABLE) writel(pff|NVREG_PFF_PAUSE_RX, base + NvRegPacketFilterFlags); else writel(pff, base + NvRegPacketFilterFlags); } if (np->pause_flags & NV_PAUSEFRAME_TX_CAPABLE) { u32 regmisc = readl(base + NvRegMisc1) & ~NVREG_MISC1_PAUSE_TX; if (np->pause_flags & NV_PAUSEFRAME_TX_ENABLE) { writel(NVREG_TX_PAUSEFRAME_ENABLE, base + NvRegTxPauseFrame); writel(regmisc|NVREG_MISC1_PAUSE_TX, base + NvRegMisc1); } else { writel(NVREG_TX_PAUSEFRAME_DISABLE, base + NvRegTxPauseFrame); writel(regmisc, base + NvRegMisc1); pause_flags = np->pause_flags; } } nv_update_pause(dev, pause_flags); return retval; } Loading Loading @@ -2597,11 +2619,15 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) if (ecmd->advertising & ADVERTISED_10baseT_Half) adv |= ADVERTISE_10HALF; if (ecmd->advertising & ADVERTISED_10baseT_Full) adv |= ADVERTISE_10FULL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; adv |= ADVERTISE_10FULL; if (ecmd->advertising & ADVERTISED_100baseT_Half) adv |= ADVERTISE_100HALF; if (ecmd->advertising & ADVERTISED_100baseT_Full) adv |= ADVERTISE_100FULL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; adv |= ADVERTISE_100FULL; if (np->pause_flags & NV_PAUSEFRAME_RX_REQ) /* for rx we set both advertisments but disable tx pause */ adv |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; if (np->pause_flags & NV_PAUSEFRAME_TX_REQ) adv |= ADVERTISE_PAUSE_ASYM; mii_rw(dev, np->phyaddr, MII_ADVERTISE, adv); if (np->gigabit == PHY_GIGABIT) { Loading @@ -2626,11 +2652,20 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) if (ecmd->speed == SPEED_10 && ecmd->duplex == DUPLEX_HALF) adv |= ADVERTISE_10HALF; if (ecmd->speed == SPEED_10 && ecmd->duplex == DUPLEX_FULL) adv |= ADVERTISE_10FULL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; adv |= ADVERTISE_10FULL; if (ecmd->speed == SPEED_100 && ecmd->duplex == DUPLEX_HALF) adv |= ADVERTISE_100HALF; if (ecmd->speed == SPEED_100 && ecmd->duplex == DUPLEX_FULL) adv |= ADVERTISE_100FULL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; 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 advertisments but disable tx pause */ adv |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; np->pause_flags |= NV_PAUSEFRAME_RX_ENABLE; } if (np->pause_flags & NV_PAUSEFRAME_TX_REQ) { adv |= ADVERTISE_PAUSE_ASYM; np->pause_flags |= NV_PAUSEFRAME_TX_ENABLE; } mii_rw(dev, np->phyaddr, MII_ADVERTISE, adv); np->fixed_mode = adv; Loading Loading @@ -2856,6 +2891,86 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri return -ENOMEM; } static void nv_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam* pause) { struct fe_priv *np = netdev_priv(dev); pause->autoneg = (np->pause_flags & NV_PAUSEFRAME_AUTONEG) != 0; pause->rx_pause = (np->pause_flags & NV_PAUSEFRAME_RX_ENABLE) != 0; pause->tx_pause = (np->pause_flags & NV_PAUSEFRAME_TX_ENABLE) != 0; } static int nv_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam* pause) { struct fe_priv *np = netdev_priv(dev); int adv, bmcr; if ((!np->autoneg && np->duplex == 0) || (np->autoneg && !pause->autoneg && np->duplex == 0)) { printk(KERN_INFO "%s: can not set pause settings when forced link is in half duplex.\n", dev->name); return -EINVAL; } if (pause->tx_pause && !(np->pause_flags & NV_PAUSEFRAME_TX_CAPABLE)) { printk(KERN_INFO "%s: hardware does not support tx pause frames.\n", dev->name); return -EINVAL; } netif_carrier_off(dev); if (netif_running(dev)) { nv_disable_irq(dev); spin_lock_bh(&dev->xmit_lock); spin_lock(&np->lock); /* stop engines */ nv_stop_rx(dev); nv_stop_tx(dev); spin_unlock(&np->lock); spin_unlock_bh(&dev->xmit_lock); } np->pause_flags &= ~(NV_PAUSEFRAME_RX_REQ|NV_PAUSEFRAME_TX_REQ); if (pause->rx_pause) np->pause_flags |= NV_PAUSEFRAME_RX_REQ; if (pause->tx_pause) np->pause_flags |= NV_PAUSEFRAME_TX_REQ; if (np->autoneg && pause->autoneg) { np->pause_flags |= NV_PAUSEFRAME_AUTONEG; adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); adv &= ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); if (np->pause_flags & NV_PAUSEFRAME_RX_REQ) /* for rx we set both advertisments but disable tx pause */ adv |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; if (np->pause_flags & NV_PAUSEFRAME_TX_REQ) adv |= ADVERTISE_PAUSE_ASYM; mii_rw(dev, np->phyaddr, MII_ADVERTISE, adv); if (netif_running(dev)) printk(KERN_INFO "%s: link down.\n", dev->name); bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); mii_rw(dev, np->phyaddr, MII_BMCR, bmcr); } else { np->pause_flags &= ~(NV_PAUSEFRAME_AUTONEG|NV_PAUSEFRAME_RX_ENABLE|NV_PAUSEFRAME_TX_ENABLE); if (pause->rx_pause) np->pause_flags |= NV_PAUSEFRAME_RX_ENABLE; if (pause->tx_pause) np->pause_flags |= NV_PAUSEFRAME_TX_ENABLE; if (!netif_running(dev)) nv_update_linkspeed(dev); else nv_update_pause(dev, np->pause_flags); } if (netif_running(dev)) { nv_start_rx(dev); nv_start_tx(dev); nv_enable_irq(dev); } return 0; } static struct ethtool_ops ops = { .get_drvinfo = nv_get_drvinfo, .get_link = ethtool_op_get_link, Loading @@ -2871,6 +2986,8 @@ static struct ethtool_ops ops = { .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, }; static void nv_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) Loading Loading @@ -3346,9 +3463,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i np->msi_flags |= NV_MSI_X_CAPABLE; } np->pause_flags = NV_PAUSEFRAME_RX_CAPABLE; np->pause_flags = NV_PAUSEFRAME_RX_CAPABLE | NV_PAUSEFRAME_RX_REQ | NV_PAUSEFRAME_AUTONEG; if (id->driver_data & DEV_HAS_PAUSEFRAME_TX) { np->pause_flags |= NV_PAUSEFRAME_TX_CAPABLE; np->pause_flags |= NV_PAUSEFRAME_TX_CAPABLE | NV_PAUSEFRAME_TX_REQ; } Loading Loading
drivers/net/forcedeth.c +176 −59 Original line number Diff line number Diff line Loading @@ -519,6 +519,9 @@ typedef union _ring_type { #define NV_PAUSEFRAME_TX_CAPABLE 0x0002 #define NV_PAUSEFRAME_RX_ENABLE 0x0004 #define NV_PAUSEFRAME_TX_ENABLE 0x0008 #define NV_PAUSEFRAME_RX_REQ 0x0010 #define NV_PAUSEFRAME_TX_REQ 0x0020 #define NV_PAUSEFRAME_AUTONEG 0x0040 /* MSI/MSI-X defines */ #define NV_MSI_X_MAX_VECTORS 8 Loading Loading @@ -1868,16 +1871,16 @@ static void nv_set_multicast(struct net_device *dev) u8 __iomem *base = get_hwbase(dev); u32 addr[2]; u32 mask[2]; u32 pff; u32 pff = readl(base + NvRegPacketFilterFlags) & NVREG_PFF_PAUSE_RX; memset(addr, 0, sizeof(addr)); memset(mask, 0, sizeof(mask)); if (dev->flags & IFF_PROMISC) { printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); pff = NVREG_PFF_PROMISC; pff |= NVREG_PFF_PROMISC; } else { pff = NVREG_PFF_MYADDR; pff |= NVREG_PFF_MYADDR; if (dev->flags & IFF_ALLMULTI || dev->mc_list) { u32 alwaysOff[2]; Loading Loading @@ -1922,6 +1925,35 @@ static void nv_set_multicast(struct net_device *dev) spin_unlock_irq(&np->lock); } void nv_update_pause(struct net_device *dev, u32 pause_flags) { struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); np->pause_flags &= ~(NV_PAUSEFRAME_TX_ENABLE | NV_PAUSEFRAME_RX_ENABLE); if (np->pause_flags & NV_PAUSEFRAME_RX_CAPABLE) { u32 pff = readl(base + NvRegPacketFilterFlags) & ~NVREG_PFF_PAUSE_RX; if (pause_flags & NV_PAUSEFRAME_RX_ENABLE) { writel(pff|NVREG_PFF_PAUSE_RX, base + NvRegPacketFilterFlags); np->pause_flags |= NV_PAUSEFRAME_RX_ENABLE; } else { writel(pff, base + NvRegPacketFilterFlags); } } if (np->pause_flags & NV_PAUSEFRAME_TX_CAPABLE) { u32 regmisc = readl(base + NvRegMisc1) & ~NVREG_MISC1_PAUSE_TX; if (pause_flags & NV_PAUSEFRAME_TX_ENABLE) { writel(NVREG_TX_PAUSEFRAME_ENABLE, base + NvRegTxPauseFrame); writel(regmisc|NVREG_MISC1_PAUSE_TX, base + NvRegMisc1); np->pause_flags |= NV_PAUSEFRAME_TX_ENABLE; } else { writel(NVREG_TX_PAUSEFRAME_DISABLE, base + NvRegTxPauseFrame); writel(regmisc, base + NvRegMisc1); } } } /** * nv_update_linkspeed: Setup the MAC according to the link partner * @dev: Network device to be configured Loading @@ -1944,7 +1976,7 @@ static int nv_update_linkspeed(struct net_device *dev) int newdup = np->duplex; int mii_status; int retval = 0; u32 control_1000, status_1000, phyreg; u32 control_1000, status_1000, phyreg, pause_flags; /* BMSR_LSTATUS is latched, read it twice: * we want the current value. Loading Loading @@ -1990,6 +2022,11 @@ static int nv_update_linkspeed(struct net_device *dev) goto set_speed; } adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); lpa = mii_rw(dev, np->phyaddr, MII_LPA, MII_READ); dprintk(KERN_DEBUG "%s: nv_update_linkspeed: PHY advertises 0x%04x, lpa 0x%04x.\n", dev->name, adv, lpa); retval = 1; if (np->gigabit == PHY_GIGABIT) { control_1000 = mii_rw(dev, np->phyaddr, MII_CTRL1000, MII_READ); Loading @@ -2005,11 +2042,6 @@ static int nv_update_linkspeed(struct net_device *dev) } } adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); lpa = mii_rw(dev, np->phyaddr, MII_LPA, MII_READ); dprintk(KERN_DEBUG "%s: nv_update_linkspeed: PHY advertises 0x%04x, lpa 0x%04x.\n", dev->name, adv, lpa); /* FIXME: handle parallel detection properly */ adv_lpa = lpa & adv; if (adv_lpa & LPA_100FULL) { Loading Loading @@ -2068,55 +2100,45 @@ static int nv_update_linkspeed(struct net_device *dev) writel(np->linkspeed, base + NvRegLinkSpeed); pci_push(base); /* setup pause frame based on advertisement and link partner */ np->pause_flags &= ~(NV_PAUSEFRAME_TX_ENABLE | NV_PAUSEFRAME_RX_ENABLE); pause_flags = 0; /* setup pause frame */ if (np->duplex != 0) { if (np->autoneg && np->pause_flags & NV_PAUSEFRAME_AUTONEG) { adv_pause = adv & (ADVERTISE_PAUSE_CAP| ADVERTISE_PAUSE_ASYM); lpa_pause = lpa & (LPA_PAUSE_CAP| LPA_PAUSE_ASYM); switch (adv_pause) { case (ADVERTISE_PAUSE_CAP): if (lpa_pause & LPA_PAUSE_CAP) { np->pause_flags |= NV_PAUSEFRAME_TX_ENABLE | NV_PAUSEFRAME_RX_ENABLE; pause_flags |= NV_PAUSEFRAME_RX_ENABLE; if (np->pause_flags & NV_PAUSEFRAME_TX_REQ) pause_flags |= NV_PAUSEFRAME_TX_ENABLE; } break; case (ADVERTISE_PAUSE_ASYM): if (lpa_pause == (LPA_PAUSE_CAP| LPA_PAUSE_ASYM)) { np->pause_flags |= NV_PAUSEFRAME_TX_ENABLE; pause_flags |= NV_PAUSEFRAME_TX_ENABLE; } break; case (ADVERTISE_PAUSE_CAP| ADVERTISE_PAUSE_ASYM): if (lpa_pause & LPA_PAUSE_CAP) { np->pause_flags |= NV_PAUSEFRAME_TX_ENABLE | NV_PAUSEFRAME_RX_ENABLE; pause_flags |= NV_PAUSEFRAME_RX_ENABLE; if (np->pause_flags & NV_PAUSEFRAME_TX_REQ) pause_flags |= NV_PAUSEFRAME_TX_ENABLE; } if (lpa_pause == LPA_PAUSE_ASYM) { np->pause_flags |= NV_PAUSEFRAME_RX_ENABLE; pause_flags |= NV_PAUSEFRAME_RX_ENABLE; } break; } } if (np->pause_flags & NV_PAUSEFRAME_RX_CAPABLE) { u32 pff = readl(base + NvRegPacketFilterFlags) & ~NVREG_PFF_PAUSE_RX; if (np->pause_flags & NV_PAUSEFRAME_RX_ENABLE) writel(pff|NVREG_PFF_PAUSE_RX, base + NvRegPacketFilterFlags); else writel(pff, base + NvRegPacketFilterFlags); } if (np->pause_flags & NV_PAUSEFRAME_TX_CAPABLE) { u32 regmisc = readl(base + NvRegMisc1) & ~NVREG_MISC1_PAUSE_TX; if (np->pause_flags & NV_PAUSEFRAME_TX_ENABLE) { writel(NVREG_TX_PAUSEFRAME_ENABLE, base + NvRegTxPauseFrame); writel(regmisc|NVREG_MISC1_PAUSE_TX, base + NvRegMisc1); } else { writel(NVREG_TX_PAUSEFRAME_DISABLE, base + NvRegTxPauseFrame); writel(regmisc, base + NvRegMisc1); pause_flags = np->pause_flags; } } nv_update_pause(dev, pause_flags); return retval; } Loading Loading @@ -2597,11 +2619,15 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) if (ecmd->advertising & ADVERTISED_10baseT_Half) adv |= ADVERTISE_10HALF; if (ecmd->advertising & ADVERTISED_10baseT_Full) adv |= ADVERTISE_10FULL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; adv |= ADVERTISE_10FULL; if (ecmd->advertising & ADVERTISED_100baseT_Half) adv |= ADVERTISE_100HALF; if (ecmd->advertising & ADVERTISED_100baseT_Full) adv |= ADVERTISE_100FULL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; adv |= ADVERTISE_100FULL; if (np->pause_flags & NV_PAUSEFRAME_RX_REQ) /* for rx we set both advertisments but disable tx pause */ adv |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; if (np->pause_flags & NV_PAUSEFRAME_TX_REQ) adv |= ADVERTISE_PAUSE_ASYM; mii_rw(dev, np->phyaddr, MII_ADVERTISE, adv); if (np->gigabit == PHY_GIGABIT) { Loading @@ -2626,11 +2652,20 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) if (ecmd->speed == SPEED_10 && ecmd->duplex == DUPLEX_HALF) adv |= ADVERTISE_10HALF; if (ecmd->speed == SPEED_10 && ecmd->duplex == DUPLEX_FULL) adv |= ADVERTISE_10FULL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; adv |= ADVERTISE_10FULL; if (ecmd->speed == SPEED_100 && ecmd->duplex == DUPLEX_HALF) adv |= ADVERTISE_100HALF; if (ecmd->speed == SPEED_100 && ecmd->duplex == DUPLEX_FULL) adv |= ADVERTISE_100FULL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; 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 advertisments but disable tx pause */ adv |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; np->pause_flags |= NV_PAUSEFRAME_RX_ENABLE; } if (np->pause_flags & NV_PAUSEFRAME_TX_REQ) { adv |= ADVERTISE_PAUSE_ASYM; np->pause_flags |= NV_PAUSEFRAME_TX_ENABLE; } mii_rw(dev, np->phyaddr, MII_ADVERTISE, adv); np->fixed_mode = adv; Loading Loading @@ -2856,6 +2891,86 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri return -ENOMEM; } static void nv_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam* pause) { struct fe_priv *np = netdev_priv(dev); pause->autoneg = (np->pause_flags & NV_PAUSEFRAME_AUTONEG) != 0; pause->rx_pause = (np->pause_flags & NV_PAUSEFRAME_RX_ENABLE) != 0; pause->tx_pause = (np->pause_flags & NV_PAUSEFRAME_TX_ENABLE) != 0; } static int nv_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam* pause) { struct fe_priv *np = netdev_priv(dev); int adv, bmcr; if ((!np->autoneg && np->duplex == 0) || (np->autoneg && !pause->autoneg && np->duplex == 0)) { printk(KERN_INFO "%s: can not set pause settings when forced link is in half duplex.\n", dev->name); return -EINVAL; } if (pause->tx_pause && !(np->pause_flags & NV_PAUSEFRAME_TX_CAPABLE)) { printk(KERN_INFO "%s: hardware does not support tx pause frames.\n", dev->name); return -EINVAL; } netif_carrier_off(dev); if (netif_running(dev)) { nv_disable_irq(dev); spin_lock_bh(&dev->xmit_lock); spin_lock(&np->lock); /* stop engines */ nv_stop_rx(dev); nv_stop_tx(dev); spin_unlock(&np->lock); spin_unlock_bh(&dev->xmit_lock); } np->pause_flags &= ~(NV_PAUSEFRAME_RX_REQ|NV_PAUSEFRAME_TX_REQ); if (pause->rx_pause) np->pause_flags |= NV_PAUSEFRAME_RX_REQ; if (pause->tx_pause) np->pause_flags |= NV_PAUSEFRAME_TX_REQ; if (np->autoneg && pause->autoneg) { np->pause_flags |= NV_PAUSEFRAME_AUTONEG; adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); adv &= ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); if (np->pause_flags & NV_PAUSEFRAME_RX_REQ) /* for rx we set both advertisments but disable tx pause */ adv |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; if (np->pause_flags & NV_PAUSEFRAME_TX_REQ) adv |= ADVERTISE_PAUSE_ASYM; mii_rw(dev, np->phyaddr, MII_ADVERTISE, adv); if (netif_running(dev)) printk(KERN_INFO "%s: link down.\n", dev->name); bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); mii_rw(dev, np->phyaddr, MII_BMCR, bmcr); } else { np->pause_flags &= ~(NV_PAUSEFRAME_AUTONEG|NV_PAUSEFRAME_RX_ENABLE|NV_PAUSEFRAME_TX_ENABLE); if (pause->rx_pause) np->pause_flags |= NV_PAUSEFRAME_RX_ENABLE; if (pause->tx_pause) np->pause_flags |= NV_PAUSEFRAME_TX_ENABLE; if (!netif_running(dev)) nv_update_linkspeed(dev); else nv_update_pause(dev, np->pause_flags); } if (netif_running(dev)) { nv_start_rx(dev); nv_start_tx(dev); nv_enable_irq(dev); } return 0; } static struct ethtool_ops ops = { .get_drvinfo = nv_get_drvinfo, .get_link = ethtool_op_get_link, Loading @@ -2871,6 +2986,8 @@ static struct ethtool_ops ops = { .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, }; static void nv_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) Loading Loading @@ -3346,9 +3463,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i np->msi_flags |= NV_MSI_X_CAPABLE; } np->pause_flags = NV_PAUSEFRAME_RX_CAPABLE; np->pause_flags = NV_PAUSEFRAME_RX_CAPABLE | NV_PAUSEFRAME_RX_REQ | NV_PAUSEFRAME_AUTONEG; if (id->driver_data & DEV_HAS_PAUSEFRAME_TX) { np->pause_flags |= NV_PAUSEFRAME_TX_CAPABLE; np->pause_flags |= NV_PAUSEFRAME_TX_CAPABLE | NV_PAUSEFRAME_TX_REQ; } Loading