static int e1000_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; /* * When SoL/IDER sessions are active, autoneg/speed/duplex * cannot be changed */ if (e1000_check_reset_block(hw)) { e_err("Cannot change link characteristics when SoL/IDER is " "active.\n"); return -EINVAL; } while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) msleep(1); if (ecmd->autoneg == AUTONEG_ENABLE) { hw->mac.autoneg = 1; if (hw->phy.media_type == e1000_media_type_fiber) hw->phy.autoneg_advertised = ADVERTISED_1000baseT_Full | ADVERTISED_FIBRE | ADVERTISED_Autoneg; else hw->phy.autoneg_advertised = ecmd->advertising | ADVERTISED_TP | ADVERTISED_Autoneg; ecmd->advertising = hw->phy.autoneg_advertised; if (adapter->fc_autoneg) hw->fc.requested_mode = e1000_fc_default; } else { if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) { clear_bit(__E1000_RESETTING, &adapter->state); return -EINVAL; } } /* reset the link */ if (netif_running(adapter->netdev)) { e1000e_down(adapter); e1000e_up(adapter); } else { e1000e_reset(adapter); } clear_bit(__E1000_RESETTING, &adapter->state); return 0; }
static int e1000_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; int retval = 0; adapter->fc_autoneg = pause->autoneg; while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) usleep_range(1000, 2000); if (adapter->fc_autoneg == AUTONEG_ENABLE) { hw->fc.requested_mode = e1000_fc_default; if (netif_running(adapter->netdev)) { e1000e_down(adapter); e1000e_up(adapter); } else { e1000e_reset(adapter); } } else { if (pause->rx_pause && pause->tx_pause) hw->fc.requested_mode = e1000_fc_full; else if (pause->rx_pause && !pause->tx_pause) hw->fc.requested_mode = e1000_fc_rx_pause; else if (!pause->rx_pause && pause->tx_pause) hw->fc.requested_mode = e1000_fc_tx_pause; else if (!pause->rx_pause && !pause->tx_pause) hw->fc.requested_mode = e1000_fc_none; hw->fc.current_mode = hw->fc.requested_mode; if (hw->phy.media_type == e1000_media_type_fiber) { retval = hw->mac.ops.setup_link(hw); /* implicit goto out */ } else { retval = e1000e_force_mac_fc(hw); if (retval) goto out; e1000e_set_fc_watermarks(hw); } } out: clear_bit(__E1000_RESETTING, &adapter->state); return retval; }
static int e1000_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_ring *temp_tx = NULL, *temp_rx = NULL; int err = 0, size = sizeof(struct e1000_ring); bool set_tx = false, set_rx = false; u16 new_rx_count, new_tx_count; if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) return -EINVAL; new_rx_count = clamp_t(u32, ring->rx_pending, E1000_MIN_RXD, E1000_MAX_RXD); new_rx_count = ALIGN(new_rx_count, REQ_RX_DESCRIPTOR_MULTIPLE); new_tx_count = clamp_t(u32, ring->tx_pending, E1000_MIN_TXD, E1000_MAX_TXD); new_tx_count = ALIGN(new_tx_count, REQ_TX_DESCRIPTOR_MULTIPLE); if ((new_tx_count == adapter->tx_ring_count) && (new_rx_count == adapter->rx_ring_count)) /* nothing to do */ return 0; while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) usleep_range(1000, 2000); if (!netif_running(adapter->netdev)) { /* Set counts now and allocate resources during open() */ adapter->tx_ring->count = new_tx_count; adapter->rx_ring->count = new_rx_count; adapter->tx_ring_count = new_tx_count; adapter->rx_ring_count = new_rx_count; goto clear_reset; } set_tx = (new_tx_count != adapter->tx_ring_count); set_rx = (new_rx_count != adapter->rx_ring_count); /* Allocate temporary storage for ring updates */ if (set_tx) { temp_tx = vmalloc(size); if (!temp_tx) { err = -ENOMEM; goto free_temp; } } if (set_rx) { temp_rx = vmalloc(size); if (!temp_rx) { err = -ENOMEM; goto free_temp; } } e1000e_down(adapter); /* * We can't just free everything and then setup again, because the * ISRs in MSI-X mode get passed pointers to the Tx and Rx ring * structs. First, attempt to allocate new resources... */ if (set_tx) { memcpy(temp_tx, adapter->tx_ring, size); temp_tx->count = new_tx_count; err = e1000e_setup_tx_resources(temp_tx); if (err) goto err_setup; } if (set_rx) { memcpy(temp_rx, adapter->rx_ring, size); temp_rx->count = new_rx_count; err = e1000e_setup_rx_resources(temp_rx); if (err) goto err_setup_rx; } /* ...then free the old resources and copy back any new ring data */ if (set_tx) { e1000e_free_tx_resources(adapter->tx_ring); memcpy(adapter->tx_ring, temp_tx, size); adapter->tx_ring_count = new_tx_count; } if (set_rx) { e1000e_free_rx_resources(adapter->rx_ring); memcpy(adapter->rx_ring, temp_rx, size); adapter->rx_ring_count = new_rx_count; } err_setup_rx: if (err && set_tx) e1000e_free_tx_resources(temp_tx); err_setup: e1000e_up(adapter); free_temp: vfree(temp_tx); vfree(temp_rx); clear_reset: clear_bit(__E1000_RESETTING, &adapter->state); return err; }
static int e1000_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; /* * When SoL/IDER sessions are active, autoneg/speed/duplex * cannot be changed */ if (hw->phy.ops.check_reset_block && hw->phy.ops.check_reset_block(hw)) { e_err("Cannot change link characteristics when SoL/IDER is active.\n"); return -EINVAL; } /* * MDI setting is only allowed when autoneg enabled because * some hardware doesn't allow MDI setting when speed or * duplex is forced. */ if (ecmd->eth_tp_mdix_ctrl) { if (hw->phy.media_type != e1000_media_type_copper) return -EOPNOTSUPP; if ((ecmd->eth_tp_mdix_ctrl != ETH_TP_MDI_AUTO) && (ecmd->autoneg != AUTONEG_ENABLE)) { e_err("forcing MDI/MDI-X state is not supported when link speed and/or duplex are forced\n"); return -EINVAL; } } while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) usleep_range(1000, 2000); if (ecmd->autoneg == AUTONEG_ENABLE) { hw->mac.autoneg = 1; if (hw->phy.media_type == e1000_media_type_fiber) hw->phy.autoneg_advertised = ADVERTISED_1000baseT_Full | ADVERTISED_FIBRE | ADVERTISED_Autoneg; else hw->phy.autoneg_advertised = ecmd->advertising | ADVERTISED_TP | ADVERTISED_Autoneg; ecmd->advertising = hw->phy.autoneg_advertised; if (adapter->fc_autoneg) hw->fc.requested_mode = e1000_fc_default; } else { u32 speed = ethtool_cmd_speed(ecmd); /* calling this overrides forced MDI setting */ if (e1000_set_spd_dplx(adapter, speed, ecmd->duplex)) { clear_bit(__E1000_RESETTING, &adapter->state); return -EINVAL; } } /* MDI-X => 2; MDI => 1; Auto => 3 */ if (ecmd->eth_tp_mdix_ctrl) { /* * fix up the value for auto (3 => 0) as zero is mapped * internally to auto */ if (ecmd->eth_tp_mdix_ctrl == ETH_TP_MDI_AUTO) hw->phy.mdix = AUTO_ALL_MODES; else hw->phy.mdix = ecmd->eth_tp_mdix_ctrl; } /* reset the link */ if (netif_running(adapter->netdev)) { e1000e_down(adapter); e1000e_up(adapter); } else e1000e_reset(adapter); clear_bit(__E1000_RESETTING, &adapter->state); return 0; }
static int e1000_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_ring *tx_ring, *tx_old; struct e1000_ring *rx_ring, *rx_old; int err; if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) return -EINVAL; while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) msleep(1); if (netif_running(adapter->netdev)) e1000e_down(adapter); tx_old = adapter->tx_ring; rx_old = adapter->rx_ring; err = -ENOMEM; tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); if (!tx_ring) goto err_alloc_tx; /* * use a memcpy to save any previously configured * items like napi structs from having to be * reinitialized */ memcpy(tx_ring, tx_old, sizeof(struct e1000_ring)); rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); if (!rx_ring) goto err_alloc_rx; memcpy(rx_ring, rx_old, sizeof(struct e1000_ring)); adapter->tx_ring = tx_ring; adapter->rx_ring = rx_ring; rx_ring->count = max(ring->rx_pending, (u32)E1000_MIN_RXD); rx_ring->count = min(rx_ring->count, (u32)(E1000_MAX_RXD)); rx_ring->count = ALIGN(rx_ring->count, REQ_RX_DESCRIPTOR_MULTIPLE); tx_ring->count = max(ring->tx_pending, (u32)E1000_MIN_TXD); tx_ring->count = min(tx_ring->count, (u32)(E1000_MAX_TXD)); tx_ring->count = ALIGN(tx_ring->count, REQ_TX_DESCRIPTOR_MULTIPLE); if (netif_running(adapter->netdev)) { /* Try to get new resources before deleting old */ err = e1000e_setup_rx_resources(adapter); if (err) goto err_setup_rx; err = e1000e_setup_tx_resources(adapter); if (err) goto err_setup_tx; /* * restore the old in order to free it, * then add in the new */ adapter->rx_ring = rx_old; adapter->tx_ring = tx_old; e1000e_free_rx_resources(adapter); e1000e_free_tx_resources(adapter); kfree(tx_old); kfree(rx_old); adapter->rx_ring = rx_ring; adapter->tx_ring = tx_ring; err = e1000e_up(adapter); if (err) goto err_setup; } clear_bit(__E1000_RESETTING, &adapter->state); return 0; err_setup_tx: e1000e_free_rx_resources(adapter); err_setup_rx: adapter->rx_ring = rx_old; adapter->tx_ring = tx_old; kfree(rx_ring); err_alloc_rx: kfree(tx_ring); err_alloc_tx: e1000e_up(adapter); err_setup: clear_bit(__E1000_RESETTING, &adapter->state); return err; }