diff options
author | Ayaz Abdulla <aabdulla@nvidia.com> | 2006-06-10 22:47:42 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-06-11 09:25:15 -0400 |
commit | b6d0773fa7943fd93d564056395a7ff29b81213b (patch) | |
tree | 119a6000893c91ed6a5aa7c29d5e84bf1aeab069 /drivers | |
parent | eafa59f6bcc6e46b756198a5388d195c4f0e671a (diff) |
[PATCH] forcedeth config: flow control
This patch allows for configurable flow control through ethtool support.
Signed-Off-By: Ayaz Abdulla <aabdulla@nvidia.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/forcedeth.c | 235 |
1 files changed, 176 insertions, 59 deletions
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index f29a5b6f37d6..14e6da2c1bf4 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c | |||
@@ -519,6 +519,9 @@ typedef union _ring_type { | |||
519 | #define NV_PAUSEFRAME_TX_CAPABLE 0x0002 | 519 | #define NV_PAUSEFRAME_TX_CAPABLE 0x0002 |
520 | #define NV_PAUSEFRAME_RX_ENABLE 0x0004 | 520 | #define NV_PAUSEFRAME_RX_ENABLE 0x0004 |
521 | #define NV_PAUSEFRAME_TX_ENABLE 0x0008 | 521 | #define NV_PAUSEFRAME_TX_ENABLE 0x0008 |
522 | #define NV_PAUSEFRAME_RX_REQ 0x0010 | ||
523 | #define NV_PAUSEFRAME_TX_REQ 0x0020 | ||
524 | #define NV_PAUSEFRAME_AUTONEG 0x0040 | ||
522 | 525 | ||
523 | /* MSI/MSI-X defines */ | 526 | /* MSI/MSI-X defines */ |
524 | #define NV_MSI_X_MAX_VECTORS 8 | 527 | #define NV_MSI_X_MAX_VECTORS 8 |
@@ -1868,16 +1871,16 @@ static void nv_set_multicast(struct net_device *dev) | |||
1868 | u8 __iomem *base = get_hwbase(dev); | 1871 | u8 __iomem *base = get_hwbase(dev); |
1869 | u32 addr[2]; | 1872 | u32 addr[2]; |
1870 | u32 mask[2]; | 1873 | u32 mask[2]; |
1871 | u32 pff; | 1874 | u32 pff = readl(base + NvRegPacketFilterFlags) & NVREG_PFF_PAUSE_RX; |
1872 | 1875 | ||
1873 | memset(addr, 0, sizeof(addr)); | 1876 | memset(addr, 0, sizeof(addr)); |
1874 | memset(mask, 0, sizeof(mask)); | 1877 | memset(mask, 0, sizeof(mask)); |
1875 | 1878 | ||
1876 | if (dev->flags & IFF_PROMISC) { | 1879 | if (dev->flags & IFF_PROMISC) { |
1877 | printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); | 1880 | printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); |
1878 | pff = NVREG_PFF_PROMISC; | 1881 | pff |= NVREG_PFF_PROMISC; |
1879 | } else { | 1882 | } else { |
1880 | pff = NVREG_PFF_MYADDR; | 1883 | pff |= NVREG_PFF_MYADDR; |
1881 | 1884 | ||
1882 | if (dev->flags & IFF_ALLMULTI || dev->mc_list) { | 1885 | if (dev->flags & IFF_ALLMULTI || dev->mc_list) { |
1883 | u32 alwaysOff[2]; | 1886 | u32 alwaysOff[2]; |
@@ -1922,6 +1925,35 @@ static void nv_set_multicast(struct net_device *dev) | |||
1922 | spin_unlock_irq(&np->lock); | 1925 | spin_unlock_irq(&np->lock); |
1923 | } | 1926 | } |
1924 | 1927 | ||
1928 | void nv_update_pause(struct net_device *dev, u32 pause_flags) | ||
1929 | { | ||
1930 | struct fe_priv *np = netdev_priv(dev); | ||
1931 | u8 __iomem *base = get_hwbase(dev); | ||
1932 | |||
1933 | np->pause_flags &= ~(NV_PAUSEFRAME_TX_ENABLE | NV_PAUSEFRAME_RX_ENABLE); | ||
1934 | |||
1935 | if (np->pause_flags & NV_PAUSEFRAME_RX_CAPABLE) { | ||
1936 | u32 pff = readl(base + NvRegPacketFilterFlags) & ~NVREG_PFF_PAUSE_RX; | ||
1937 | if (pause_flags & NV_PAUSEFRAME_RX_ENABLE) { | ||
1938 | writel(pff|NVREG_PFF_PAUSE_RX, base + NvRegPacketFilterFlags); | ||
1939 | np->pause_flags |= NV_PAUSEFRAME_RX_ENABLE; | ||
1940 | } else { | ||
1941 | writel(pff, base + NvRegPacketFilterFlags); | ||
1942 | } | ||
1943 | } | ||
1944 | if (np->pause_flags & NV_PAUSEFRAME_TX_CAPABLE) { | ||
1945 | u32 regmisc = readl(base + NvRegMisc1) & ~NVREG_MISC1_PAUSE_TX; | ||
1946 | if (pause_flags & NV_PAUSEFRAME_TX_ENABLE) { | ||
1947 | writel(NVREG_TX_PAUSEFRAME_ENABLE, base + NvRegTxPauseFrame); | ||
1948 | writel(regmisc|NVREG_MISC1_PAUSE_TX, base + NvRegMisc1); | ||
1949 | np->pause_flags |= NV_PAUSEFRAME_TX_ENABLE; | ||
1950 | } else { | ||
1951 | writel(NVREG_TX_PAUSEFRAME_DISABLE, base + NvRegTxPauseFrame); | ||
1952 | writel(regmisc, base + NvRegMisc1); | ||
1953 | } | ||
1954 | } | ||
1955 | } | ||
1956 | |||
1925 | /** | 1957 | /** |
1926 | * nv_update_linkspeed: Setup the MAC according to the link partner | 1958 | * nv_update_linkspeed: Setup the MAC according to the link partner |
1927 | * @dev: Network device to be configured | 1959 | * @dev: Network device to be configured |
@@ -1944,7 +1976,7 @@ static int nv_update_linkspeed(struct net_device *dev) | |||
1944 | int newdup = np->duplex; | 1976 | int newdup = np->duplex; |
1945 | int mii_status; | 1977 | int mii_status; |
1946 | int retval = 0; | 1978 | int retval = 0; |
1947 | u32 control_1000, status_1000, phyreg; | 1979 | u32 control_1000, status_1000, phyreg, pause_flags; |
1948 | 1980 | ||
1949 | /* BMSR_LSTATUS is latched, read it twice: | 1981 | /* BMSR_LSTATUS is latched, read it twice: |
1950 | * we want the current value. | 1982 | * we want the current value. |
@@ -1990,6 +2022,11 @@ static int nv_update_linkspeed(struct net_device *dev) | |||
1990 | goto set_speed; | 2022 | goto set_speed; |
1991 | } | 2023 | } |
1992 | 2024 | ||
2025 | adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); | ||
2026 | lpa = mii_rw(dev, np->phyaddr, MII_LPA, MII_READ); | ||
2027 | dprintk(KERN_DEBUG "%s: nv_update_linkspeed: PHY advertises 0x%04x, lpa 0x%04x.\n", | ||
2028 | dev->name, adv, lpa); | ||
2029 | |||
1993 | retval = 1; | 2030 | retval = 1; |
1994 | if (np->gigabit == PHY_GIGABIT) { | 2031 | if (np->gigabit == PHY_GIGABIT) { |
1995 | control_1000 = mii_rw(dev, np->phyaddr, MII_CTRL1000, MII_READ); | 2032 | control_1000 = mii_rw(dev, np->phyaddr, MII_CTRL1000, MII_READ); |
@@ -2005,11 +2042,6 @@ static int nv_update_linkspeed(struct net_device *dev) | |||
2005 | } | 2042 | } |
2006 | } | 2043 | } |
2007 | 2044 | ||
2008 | adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); | ||
2009 | lpa = mii_rw(dev, np->phyaddr, MII_LPA, MII_READ); | ||
2010 | dprintk(KERN_DEBUG "%s: nv_update_linkspeed: PHY advertises 0x%04x, lpa 0x%04x.\n", | ||
2011 | dev->name, adv, lpa); | ||
2012 | |||
2013 | /* FIXME: handle parallel detection properly */ | 2045 | /* FIXME: handle parallel detection properly */ |
2014 | adv_lpa = lpa & adv; | 2046 | adv_lpa = lpa & adv; |
2015 | if (adv_lpa & LPA_100FULL) { | 2047 | if (adv_lpa & LPA_100FULL) { |
@@ -2068,55 +2100,45 @@ set_speed: | |||
2068 | writel(np->linkspeed, base + NvRegLinkSpeed); | 2100 | writel(np->linkspeed, base + NvRegLinkSpeed); |
2069 | pci_push(base); | 2101 | pci_push(base); |
2070 | 2102 | ||
2071 | /* setup pause frame based on advertisement and link partner */ | 2103 | pause_flags = 0; |
2072 | np->pause_flags &= ~(NV_PAUSEFRAME_TX_ENABLE | NV_PAUSEFRAME_RX_ENABLE); | 2104 | /* setup pause frame */ |
2073 | |||
2074 | if (np->duplex != 0) { | 2105 | if (np->duplex != 0) { |
2075 | adv_pause = adv & (ADVERTISE_PAUSE_CAP| ADVERTISE_PAUSE_ASYM); | 2106 | if (np->autoneg && np->pause_flags & NV_PAUSEFRAME_AUTONEG) { |
2076 | lpa_pause = lpa & (LPA_PAUSE_CAP| LPA_PAUSE_ASYM); | 2107 | adv_pause = adv & (ADVERTISE_PAUSE_CAP| ADVERTISE_PAUSE_ASYM); |
2077 | 2108 | lpa_pause = lpa & (LPA_PAUSE_CAP| LPA_PAUSE_ASYM); | |
2078 | switch (adv_pause) { | 2109 | |
2079 | case (ADVERTISE_PAUSE_CAP): | 2110 | switch (adv_pause) { |
2080 | if (lpa_pause & LPA_PAUSE_CAP) { | 2111 | case (ADVERTISE_PAUSE_CAP): |
2081 | np->pause_flags |= NV_PAUSEFRAME_TX_ENABLE | NV_PAUSEFRAME_RX_ENABLE; | 2112 | if (lpa_pause & LPA_PAUSE_CAP) { |
2082 | } | 2113 | pause_flags |= NV_PAUSEFRAME_RX_ENABLE; |
2083 | break; | 2114 | if (np->pause_flags & NV_PAUSEFRAME_TX_REQ) |
2084 | case (ADVERTISE_PAUSE_ASYM): | 2115 | pause_flags |= NV_PAUSEFRAME_TX_ENABLE; |
2085 | if (lpa_pause == (LPA_PAUSE_CAP| LPA_PAUSE_ASYM)) | 2116 | } |
2086 | { | 2117 | break; |
2087 | np->pause_flags |= NV_PAUSEFRAME_TX_ENABLE; | 2118 | case (ADVERTISE_PAUSE_ASYM): |
2088 | } | 2119 | if (lpa_pause == (LPA_PAUSE_CAP| LPA_PAUSE_ASYM)) |
2089 | break; | 2120 | { |
2090 | case (ADVERTISE_PAUSE_CAP| ADVERTISE_PAUSE_ASYM): | 2121 | pause_flags |= NV_PAUSEFRAME_TX_ENABLE; |
2091 | if (lpa_pause & LPA_PAUSE_CAP) | 2122 | } |
2092 | { | 2123 | break; |
2093 | np->pause_flags |= NV_PAUSEFRAME_TX_ENABLE | NV_PAUSEFRAME_RX_ENABLE; | 2124 | case (ADVERTISE_PAUSE_CAP| ADVERTISE_PAUSE_ASYM): |
2094 | } | 2125 | if (lpa_pause & LPA_PAUSE_CAP) |
2095 | if (lpa_pause == LPA_PAUSE_ASYM) | 2126 | { |
2096 | { | 2127 | pause_flags |= NV_PAUSEFRAME_RX_ENABLE; |
2097 | np->pause_flags |= NV_PAUSEFRAME_RX_ENABLE; | 2128 | if (np->pause_flags & NV_PAUSEFRAME_TX_REQ) |
2129 | pause_flags |= NV_PAUSEFRAME_TX_ENABLE; | ||
2130 | } | ||
2131 | if (lpa_pause == LPA_PAUSE_ASYM) | ||
2132 | { | ||
2133 | pause_flags |= NV_PAUSEFRAME_RX_ENABLE; | ||
2134 | } | ||
2135 | break; | ||
2098 | } | 2136 | } |
2099 | break; | ||
2100 | } | ||
2101 | } | ||
2102 | |||
2103 | if (np->pause_flags & NV_PAUSEFRAME_RX_CAPABLE) { | ||
2104 | u32 pff = readl(base + NvRegPacketFilterFlags) & ~NVREG_PFF_PAUSE_RX; | ||
2105 | if (np->pause_flags & NV_PAUSEFRAME_RX_ENABLE) | ||
2106 | writel(pff|NVREG_PFF_PAUSE_RX, base + NvRegPacketFilterFlags); | ||
2107 | else | ||
2108 | writel(pff, base + NvRegPacketFilterFlags); | ||
2109 | } | ||
2110 | if (np->pause_flags & NV_PAUSEFRAME_TX_CAPABLE) { | ||
2111 | u32 regmisc = readl(base + NvRegMisc1) & ~NVREG_MISC1_PAUSE_TX; | ||
2112 | if (np->pause_flags & NV_PAUSEFRAME_TX_ENABLE) { | ||
2113 | writel(NVREG_TX_PAUSEFRAME_ENABLE, base + NvRegTxPauseFrame); | ||
2114 | writel(regmisc|NVREG_MISC1_PAUSE_TX, base + NvRegMisc1); | ||
2115 | } else { | 2137 | } else { |
2116 | writel(NVREG_TX_PAUSEFRAME_DISABLE, base + NvRegTxPauseFrame); | 2138 | pause_flags = np->pause_flags; |
2117 | writel(regmisc, base + NvRegMisc1); | ||
2118 | } | 2139 | } |
2119 | } | 2140 | } |
2141 | nv_update_pause(dev, pause_flags); | ||
2120 | 2142 | ||
2121 | return retval; | 2143 | return retval; |
2122 | } | 2144 | } |
@@ -2597,11 +2619,15 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) | |||
2597 | if (ecmd->advertising & ADVERTISED_10baseT_Half) | 2619 | if (ecmd->advertising & ADVERTISED_10baseT_Half) |
2598 | adv |= ADVERTISE_10HALF; | 2620 | adv |= ADVERTISE_10HALF; |
2599 | if (ecmd->advertising & ADVERTISED_10baseT_Full) | 2621 | if (ecmd->advertising & ADVERTISED_10baseT_Full) |
2600 | adv |= ADVERTISE_10FULL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; | 2622 | adv |= ADVERTISE_10FULL; |
2601 | if (ecmd->advertising & ADVERTISED_100baseT_Half) | 2623 | if (ecmd->advertising & ADVERTISED_100baseT_Half) |
2602 | adv |= ADVERTISE_100HALF; | 2624 | adv |= ADVERTISE_100HALF; |
2603 | if (ecmd->advertising & ADVERTISED_100baseT_Full) | 2625 | if (ecmd->advertising & ADVERTISED_100baseT_Full) |
2604 | adv |= ADVERTISE_100FULL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; | 2626 | adv |= ADVERTISE_100FULL; |
2627 | if (np->pause_flags & NV_PAUSEFRAME_RX_REQ) /* for rx we set both advertisments but disable tx pause */ | ||
2628 | adv |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; | ||
2629 | if (np->pause_flags & NV_PAUSEFRAME_TX_REQ) | ||
2630 | adv |= ADVERTISE_PAUSE_ASYM; | ||
2605 | mii_rw(dev, np->phyaddr, MII_ADVERTISE, adv); | 2631 | mii_rw(dev, np->phyaddr, MII_ADVERTISE, adv); |
2606 | 2632 | ||
2607 | if (np->gigabit == PHY_GIGABIT) { | 2633 | if (np->gigabit == PHY_GIGABIT) { |
@@ -2626,11 +2652,20 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) | |||
2626 | if (ecmd->speed == SPEED_10 && ecmd->duplex == DUPLEX_HALF) | 2652 | if (ecmd->speed == SPEED_10 && ecmd->duplex == DUPLEX_HALF) |
2627 | adv |= ADVERTISE_10HALF; | 2653 | adv |= ADVERTISE_10HALF; |
2628 | if (ecmd->speed == SPEED_10 && ecmd->duplex == DUPLEX_FULL) | 2654 | if (ecmd->speed == SPEED_10 && ecmd->duplex == DUPLEX_FULL) |
2629 | adv |= ADVERTISE_10FULL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; | 2655 | adv |= ADVERTISE_10FULL; |
2630 | if (ecmd->speed == SPEED_100 && ecmd->duplex == DUPLEX_HALF) | 2656 | if (ecmd->speed == SPEED_100 && ecmd->duplex == DUPLEX_HALF) |
2631 | adv |= ADVERTISE_100HALF; | 2657 | adv |= ADVERTISE_100HALF; |
2632 | if (ecmd->speed == SPEED_100 && ecmd->duplex == DUPLEX_FULL) | 2658 | if (ecmd->speed == SPEED_100 && ecmd->duplex == DUPLEX_FULL) |
2633 | adv |= ADVERTISE_100FULL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; | 2659 | adv |= ADVERTISE_100FULL; |
2660 | np->pause_flags &= ~(NV_PAUSEFRAME_AUTONEG|NV_PAUSEFRAME_RX_ENABLE|NV_PAUSEFRAME_TX_ENABLE); | ||
2661 | if (np->pause_flags & NV_PAUSEFRAME_RX_REQ) {/* for rx we set both advertisments but disable tx pause */ | ||
2662 | adv |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; | ||
2663 | np->pause_flags |= NV_PAUSEFRAME_RX_ENABLE; | ||
2664 | } | ||
2665 | if (np->pause_flags & NV_PAUSEFRAME_TX_REQ) { | ||
2666 | adv |= ADVERTISE_PAUSE_ASYM; | ||
2667 | np->pause_flags |= NV_PAUSEFRAME_TX_ENABLE; | ||
2668 | } | ||
2634 | mii_rw(dev, np->phyaddr, MII_ADVERTISE, adv); | 2669 | mii_rw(dev, np->phyaddr, MII_ADVERTISE, adv); |
2635 | np->fixed_mode = adv; | 2670 | np->fixed_mode = adv; |
2636 | 2671 | ||
@@ -2856,6 +2891,86 @@ exit: | |||
2856 | return -ENOMEM; | 2891 | return -ENOMEM; |
2857 | } | 2892 | } |
2858 | 2893 | ||
2894 | static void nv_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam* pause) | ||
2895 | { | ||
2896 | struct fe_priv *np = netdev_priv(dev); | ||
2897 | |||
2898 | pause->autoneg = (np->pause_flags & NV_PAUSEFRAME_AUTONEG) != 0; | ||
2899 | pause->rx_pause = (np->pause_flags & NV_PAUSEFRAME_RX_ENABLE) != 0; | ||
2900 | pause->tx_pause = (np->pause_flags & NV_PAUSEFRAME_TX_ENABLE) != 0; | ||
2901 | } | ||
2902 | |||
2903 | static int nv_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam* pause) | ||
2904 | { | ||
2905 | struct fe_priv *np = netdev_priv(dev); | ||
2906 | int adv, bmcr; | ||
2907 | |||
2908 | if ((!np->autoneg && np->duplex == 0) || | ||
2909 | (np->autoneg && !pause->autoneg && np->duplex == 0)) { | ||
2910 | printk(KERN_INFO "%s: can not set pause settings when forced link is in half duplex.\n", | ||
2911 | dev->name); | ||
2912 | return -EINVAL; | ||
2913 | } | ||
2914 | if (pause->tx_pause && !(np->pause_flags & NV_PAUSEFRAME_TX_CAPABLE)) { | ||
2915 | printk(KERN_INFO "%s: hardware does not support tx pause frames.\n", dev->name); | ||
2916 | return -EINVAL; | ||
2917 | } | ||
2918 | |||
2919 | netif_carrier_off(dev); | ||
2920 | if (netif_running(dev)) { | ||
2921 | nv_disable_irq(dev); | ||
2922 | spin_lock_bh(&dev->xmit_lock); | ||
2923 | spin_lock(&np->lock); | ||
2924 | /* stop engines */ | ||
2925 | nv_stop_rx(dev); | ||
2926 | nv_stop_tx(dev); | ||
2927 | spin_unlock(&np->lock); | ||
2928 | spin_unlock_bh(&dev->xmit_lock); | ||
2929 | } | ||
2930 | |||
2931 | np->pause_flags &= ~(NV_PAUSEFRAME_RX_REQ|NV_PAUSEFRAME_TX_REQ); | ||
2932 | if (pause->rx_pause) | ||
2933 | np->pause_flags |= NV_PAUSEFRAME_RX_REQ; | ||
2934 | if (pause->tx_pause) | ||
2935 | np->pause_flags |= NV_PAUSEFRAME_TX_REQ; | ||
2936 | |||
2937 | if (np->autoneg && pause->autoneg) { | ||
2938 | np->pause_flags |= NV_PAUSEFRAME_AUTONEG; | ||
2939 | |||
2940 | adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); | ||
2941 | adv &= ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); | ||
2942 | if (np->pause_flags & NV_PAUSEFRAME_RX_REQ) /* for rx we set both advertisments but disable tx pause */ | ||
2943 | adv |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; | ||
2944 | if (np->pause_flags & NV_PAUSEFRAME_TX_REQ) | ||
2945 | adv |= ADVERTISE_PAUSE_ASYM; | ||
2946 | mii_rw(dev, np->phyaddr, MII_ADVERTISE, adv); | ||
2947 | |||
2948 | if (netif_running(dev)) | ||
2949 | printk(KERN_INFO "%s: link down.\n", dev->name); | ||
2950 | bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); | ||
2951 | bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); | ||
2952 | mii_rw(dev, np->phyaddr, MII_BMCR, bmcr); | ||
2953 | } else { | ||
2954 | np->pause_flags &= ~(NV_PAUSEFRAME_AUTONEG|NV_PAUSEFRAME_RX_ENABLE|NV_PAUSEFRAME_TX_ENABLE); | ||
2955 | if (pause->rx_pause) | ||
2956 | np->pause_flags |= NV_PAUSEFRAME_RX_ENABLE; | ||
2957 | if (pause->tx_pause) | ||
2958 | np->pause_flags |= NV_PAUSEFRAME_TX_ENABLE; | ||
2959 | |||
2960 | if (!netif_running(dev)) | ||
2961 | nv_update_linkspeed(dev); | ||
2962 | else | ||
2963 | nv_update_pause(dev, np->pause_flags); | ||
2964 | } | ||
2965 | |||
2966 | if (netif_running(dev)) { | ||
2967 | nv_start_rx(dev); | ||
2968 | nv_start_tx(dev); | ||
2969 | nv_enable_irq(dev); | ||
2970 | } | ||
2971 | return 0; | ||
2972 | } | ||
2973 | |||
2859 | static struct ethtool_ops ops = { | 2974 | static struct ethtool_ops ops = { |
2860 | .get_drvinfo = nv_get_drvinfo, | 2975 | .get_drvinfo = nv_get_drvinfo, |
2861 | .get_link = ethtool_op_get_link, | 2976 | .get_link = ethtool_op_get_link, |
@@ -2871,6 +2986,8 @@ static struct ethtool_ops ops = { | |||
2871 | .set_tso = nv_set_tso, | 2986 | .set_tso = nv_set_tso, |
2872 | .get_ringparam = nv_get_ringparam, | 2987 | .get_ringparam = nv_get_ringparam, |
2873 | .set_ringparam = nv_set_ringparam, | 2988 | .set_ringparam = nv_set_ringparam, |
2989 | .get_pauseparam = nv_get_pauseparam, | ||
2990 | .set_pauseparam = nv_set_pauseparam, | ||
2874 | }; | 2991 | }; |
2875 | 2992 | ||
2876 | static void nv_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) | 2993 | static void nv_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) |
@@ -3346,9 +3463,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i | |||
3346 | np->msi_flags |= NV_MSI_X_CAPABLE; | 3463 | np->msi_flags |= NV_MSI_X_CAPABLE; |
3347 | } | 3464 | } |
3348 | 3465 | ||
3349 | np->pause_flags = NV_PAUSEFRAME_RX_CAPABLE; | 3466 | np->pause_flags = NV_PAUSEFRAME_RX_CAPABLE | NV_PAUSEFRAME_RX_REQ | NV_PAUSEFRAME_AUTONEG; |
3350 | if (id->driver_data & DEV_HAS_PAUSEFRAME_TX) { | 3467 | if (id->driver_data & DEV_HAS_PAUSEFRAME_TX) { |
3351 | np->pause_flags |= NV_PAUSEFRAME_TX_CAPABLE; | 3468 | np->pause_flags |= NV_PAUSEFRAME_TX_CAPABLE | NV_PAUSEFRAME_TX_REQ; |
3352 | } | 3469 | } |
3353 | 3470 | ||
3354 | 3471 | ||