aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/forcedeth.c
diff options
context:
space:
mode:
authorAyaz Abdulla <aabdulla@nvidia.com>2006-06-10 22:47:42 -0400
committerJeff Garzik <jeff@garzik.org>2006-06-11 09:25:15 -0400
commitb6d0773fa7943fd93d564056395a7ff29b81213b (patch)
tree119a6000893c91ed6a5aa7c29d5e84bf1aeab069 /drivers/net/forcedeth.c
parenteafa59f6bcc6e46b756198a5388d195c4f0e671a (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/net/forcedeth.c')
-rw-r--r--drivers/net/forcedeth.c235
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
1928void 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
2894static 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
2903static 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
2859static struct ethtool_ops ops = { 2974static 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
2876static void nv_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) 2993static 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