]> git.hungrycats.org Git - linux/commitdiff
[e1000] add ethtool flow control support
authorScott Feldman <scott.feldman@intel.com>
Thu, 11 Sep 2003 11:11:02 +0000 (07:11 -0400)
committerStephen Hemminger <shemminger@osdl.org>
Thu, 11 Sep 2003 11:11:02 +0000 (07:11 -0400)
* Add ethtool flow control support

drivers/net/e1000/e1000.h
drivers/net/e1000/e1000_ethtool.c
drivers/net/e1000/e1000_hw.c
drivers/net/e1000/e1000_hw.h
drivers/net/e1000/e1000_param.c

index 80bc150c83c3af37fefc72fcda3cc7318358019b..837f93d4cc3ab235f46aa250a59e4faf1dc1e154 100644 (file)
@@ -180,6 +180,7 @@ struct e1000_adapter {
        spinlock_t stats_lock;
        atomic_t irq_sem;
        struct work_struct tx_timeout_task;
+       uint8_t fc_autoneg;
 
        struct timer_list blink_timer;
        unsigned long led_status;
index 71677a1f7ee57d0717962697d90c5d2d33e4561e..fa10ebaf6755cc7bce61a51d0d4185ce852e5678 100644 (file)
@@ -190,6 +190,55 @@ e1000_ethtool_sset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
        return 0;
 }
 
+static int
+e1000_ethtool_gpause(struct e1000_adapter *adapter,
+                     struct ethtool_pauseparam *epause)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       
+       epause->autoneg = 
+               (adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
+       
+       if(hw->fc == e1000_fc_rx_pause)
+               epause->rx_pause = 1;
+       else if(hw->fc == e1000_fc_tx_pause)
+               epause->tx_pause = 1;
+       else if(hw->fc == e1000_fc_full) {
+               epause->rx_pause = 1;
+               epause->tx_pause = 1;
+       }
+       
+       return 0;
+}
+
+static int
+e1000_ethtool_spause(struct e1000_adapter *adapter,
+                     struct ethtool_pauseparam *epause)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       
+       adapter->fc_autoneg = epause->autoneg;
+
+       if(epause->rx_pause && epause->tx_pause)
+               hw->fc = e1000_fc_full;
+       else if(epause->rx_pause && !epause->tx_pause)
+               hw->fc = e1000_fc_rx_pause;
+       else if(!epause->rx_pause && epause->tx_pause)
+               hw->fc = e1000_fc_tx_pause;
+       else if(!epause->rx_pause && !epause->tx_pause)
+               hw->fc = e1000_fc_none;
+
+       hw->original_fc = hw->fc;
+
+       if(netif_running(adapter->netdev)) {
+               e1000_down(adapter);
+               e1000_up(adapter);
+       } else
+               e1000_reset(adapter);
+       
+       return 0;
+}
+
 static void
 e1000_ethtool_gdrvinfo(struct e1000_adapter *adapter,
                        struct ethtool_drvinfo *drvinfo)
@@ -1449,6 +1498,19 @@ err_geeprom_ioctl:
                addr += offsetof(struct ethtool_eeprom, data);
                return e1000_ethtool_seeprom(adapter, &eeprom, addr);
        }
+       case ETHTOOL_GPAUSEPARAM: {
+               struct ethtool_pauseparam epause = {ETHTOOL_GPAUSEPARAM};
+               e1000_ethtool_gpause(adapter, &epause);
+               if(copy_to_user(addr, &epause, sizeof(epause)))
+                       return -EFAULT;
+               return 0;
+       }
+       case ETHTOOL_SPAUSEPARAM: {
+               struct ethtool_pauseparam epause;
+               if(copy_from_user(&epause, addr, sizeof(epause)))
+                       return -EFAULT;
+               return e1000_ethtool_spause(adapter, &epause);
+       }
        case ETHTOOL_GSTATS: {
                struct {
                        struct ethtool_stats eth_stats;
index 51a1fc3e3b6e8970d8c922ccf4b546e7550c5e21..70a5ad99fef787fbdec710010c5cff1af39879ac 100644 (file)
@@ -39,7 +39,6 @@ static int32_t e1000_setup_fiber_serdes_link(struct e1000_hw *hw);
 static int32_t e1000_adjust_serdes_amplitude(struct e1000_hw *hw);
 static int32_t e1000_phy_force_speed_duplex(struct e1000_hw *hw);
 static int32_t e1000_config_mac_to_phy(struct e1000_hw *hw);
-static int32_t e1000_force_mac_fc(struct e1000_hw *hw);
 static void e1000_raise_mdi_clk(struct e1000_hw *hw, uint32_t *ctrl);
 static void e1000_lower_mdi_clk(struct e1000_hw *hw, uint32_t *ctrl);
 static void e1000_shift_out_mdi_bits(struct e1000_hw *hw, uint32_t data, uint16_t count);
@@ -1629,7 +1628,7 @@ e1000_config_mac_to_phy(struct e1000_hw *hw)
  * by the PHY rather than the MAC. Software must also configure these
  * bits when link is forced on a fiber connection.
  *****************************************************************************/
-static int32_t
+int32_t
 e1000_force_mac_fc(struct e1000_hw *hw)
 {
     uint32_t ctrl;
@@ -1682,7 +1681,7 @@ e1000_force_mac_fc(struct e1000_hw *hw)
         ctrl &= (~E1000_CTRL_TFCE);
 
     E1000_WRITE_REG(hw, CTRL, ctrl);
-    return 0;
+    return E1000_SUCCESS;
 }
 
 /******************************************************************************
index d2b596c47767b6e5adbcd88aa1db05e145b149dc..b05a298962862b41b0c0eb32694905f210efc1b0 100644 (file)
@@ -264,6 +264,7 @@ int32_t e1000_config_fc_after_link_up(struct e1000_hw *hw);
 int32_t e1000_check_for_link(struct e1000_hw *hw);
 int32_t e1000_get_speed_and_duplex(struct e1000_hw *hw, uint16_t * speed, uint16_t * duplex);
 int32_t e1000_wait_autoneg(struct e1000_hw *hw);
+int32_t e1000_force_mac_fc(struct e1000_hw *hw);
 
 /* PHY */
 int32_t e1000_read_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *phy_data);
index c3511079a77ad919fbe91af8474fa13ac934f716..820e3ad61c5afc3cea62abcaee5a4baf6ea994a8 100644 (file)
@@ -140,7 +140,7 @@ E1000_PARAM(FlowControl, "Flow Control setting");
  * Valid Range: 0, 1
  *  - 0 - disables all checksum offload
  *  - 1 - enables receive IP/TCP/UDP checksum offload
- *        on 82543 based NICs
+ *        on 82543 and newer -based NICs
  *
  * Default Value: 1
  */
@@ -602,7 +602,7 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
 
        switch (speed + dplx) {
        case 0:
-               adapter->hw.autoneg = 1;
+               adapter->hw.autoneg = adapter->fc_autoneg = 1;
                if(Speed[bd] != OPTION_UNSET || Duplex[bd] != OPTION_UNSET)
                        printk(KERN_INFO
                               "Speed and duplex autonegotiation enabled\n");
@@ -610,14 +610,14 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
        case HALF_DUPLEX:
                printk(KERN_INFO "Half Duplex specified without Speed\n");
                printk(KERN_INFO "Using Autonegotiation at Half Duplex only\n");
-               adapter->hw.autoneg = 1;
+               adapter->hw.autoneg = adapter->fc_autoneg = 1;
                adapter->hw.autoneg_advertised = ADVERTISE_10_HALF |
                                                 ADVERTISE_100_HALF;
                break;
        case FULL_DUPLEX:
                printk(KERN_INFO "Full Duplex specified without Speed\n");
                printk(KERN_INFO "Using Autonegotiation at Full Duplex only\n");
-               adapter->hw.autoneg = 1;
+               adapter->hw.autoneg = adapter->fc_autoneg = 1;
                adapter->hw.autoneg_advertised = ADVERTISE_10_FULL |
                                                 ADVERTISE_100_FULL |
                                                 ADVERTISE_1000_FULL;
@@ -625,38 +625,38 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
        case SPEED_10:
                printk(KERN_INFO "10 Mbps Speed specified without Duplex\n");
                printk(KERN_INFO "Using Autonegotiation at 10 Mbps only\n");
-               adapter->hw.autoneg = 1;
+               adapter->hw.autoneg = adapter->fc_autoneg = 1;
                adapter->hw.autoneg_advertised = ADVERTISE_10_HALF |
                                                 ADVERTISE_10_FULL;
                break;
        case SPEED_10 + HALF_DUPLEX:
                printk(KERN_INFO "Forcing to 10 Mbps Half Duplex\n");
-               adapter->hw.autoneg = 0;
+               adapter->hw.autoneg = adapter->fc_autoneg = 0;
                adapter->hw.forced_speed_duplex = e1000_10_half;
                adapter->hw.autoneg_advertised = 0;
                break;
        case SPEED_10 + FULL_DUPLEX:
                printk(KERN_INFO "Forcing to 10 Mbps Full Duplex\n");
-               adapter->hw.autoneg = 0;
+               adapter->hw.autoneg = adapter->fc_autoneg = 0;
                adapter->hw.forced_speed_duplex = e1000_10_full;
                adapter->hw.autoneg_advertised = 0;
                break;
        case SPEED_100:
                printk(KERN_INFO "100 Mbps Speed specified without Duplex\n");
                printk(KERN_INFO "Using Autonegotiation at 100 Mbps only\n");
-               adapter->hw.autoneg = 1;
+               adapter->hw.autoneg = adapter->fc_autoneg = 1;
                adapter->hw.autoneg_advertised = ADVERTISE_100_HALF |
                                                 ADVERTISE_100_FULL;
                break;
        case SPEED_100 + HALF_DUPLEX:
                printk(KERN_INFO "Forcing to 100 Mbps Half Duplex\n");
-               adapter->hw.autoneg = 0;
+               adapter->hw.autoneg = adapter->fc_autoneg = 0;
                adapter->hw.forced_speed_duplex = e1000_100_half;
                adapter->hw.autoneg_advertised = 0;
                break;
        case SPEED_100 + FULL_DUPLEX:
                printk(KERN_INFO "Forcing to 100 Mbps Full Duplex\n");
-               adapter->hw.autoneg = 0;
+               adapter->hw.autoneg = adapter->fc_autoneg = 0;
                adapter->hw.forced_speed_duplex = e1000_100_full;
                adapter->hw.autoneg_advertised = 0;
                break;
@@ -664,20 +664,20 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
                printk(KERN_INFO "1000 Mbps Speed specified without Duplex\n");
                printk(KERN_INFO
                       "Using Autonegotiation at 1000 Mbps Full Duplex only\n");
-               adapter->hw.autoneg = 1;
+               adapter->hw.autoneg = adapter->fc_autoneg = 1;
                adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
                break;
        case SPEED_1000 + HALF_DUPLEX:
                printk(KERN_INFO "Half Duplex is not supported at 1000 Mbps\n");
                printk(KERN_INFO
                       "Using Autonegotiation at 1000 Mbps Full Duplex only\n");
-               adapter->hw.autoneg = 1;
+               adapter->hw.autoneg = adapter->fc_autoneg = 1;
                adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
                break;
        case SPEED_1000 + FULL_DUPLEX:
                printk(KERN_INFO
                       "Using Autonegotiation at 1000 Mbps Full Duplex only\n");
-               adapter->hw.autoneg = 1;
+               adapter->hw.autoneg = adapter->fc_autoneg = 1;
                adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
                break;
        default: