|
@@ -605,94 +605,112 @@ static void e1000_get_ringparam(struct net_device *netdev,
|
|
|
struct ethtool_ringparam *ring)
|
|
|
{
|
|
|
struct e1000_adapter *adapter = netdev_priv(netdev);
|
|
|
- struct e1000_ring *tx_ring = adapter->tx_ring;
|
|
|
- struct e1000_ring *rx_ring = adapter->rx_ring;
|
|
|
|
|
|
ring->rx_max_pending = E1000_MAX_RXD;
|
|
|
ring->tx_max_pending = E1000_MAX_TXD;
|
|
|
- ring->rx_pending = rx_ring->count;
|
|
|
- ring->tx_pending = tx_ring->count;
|
|
|
+ ring->rx_pending = adapter->rx_ring_count;
|
|
|
+ ring->tx_pending = adapter->tx_ring_count;
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
+ 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;
|
|
|
|
|
|
- while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
|
|
|
- usleep_range(1000, 2000);
|
|
|
+ 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);
|
|
|
|
|
|
- if (netif_running(adapter->netdev))
|
|
|
- e1000e_down(adapter);
|
|
|
+ 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);
|
|
|
|
|
|
- tx_old = adapter->tx_ring;
|
|
|
- rx_old = adapter->rx_ring;
|
|
|
+ if ((new_tx_count == adapter->tx_ring_count) &&
|
|
|
+ (new_rx_count == adapter->rx_ring_count))
|
|
|
+ /* nothing to do */
|
|
|
+ return 0;
|
|
|
|
|
|
- err = -ENOMEM;
|
|
|
- tx_ring = kmemdup(tx_old, sizeof(struct e1000_ring), GFP_KERNEL);
|
|
|
- if (!tx_ring)
|
|
|
- goto err_alloc_tx;
|
|
|
+ while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
|
|
|
+ usleep_range(1000, 2000);
|
|
|
|
|
|
- rx_ring = kmemdup(rx_old, sizeof(struct e1000_ring), GFP_KERNEL);
|
|
|
- if (!rx_ring)
|
|
|
- goto err_alloc_rx;
|
|
|
+ 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;
|
|
|
+ }
|
|
|
|
|
|
- adapter->tx_ring = tx_ring;
|
|
|
- adapter->rx_ring = rx_ring;
|
|
|
+ set_tx = (new_tx_count != adapter->tx_ring_count);
|
|
|
+ set_rx = (new_rx_count != adapter->rx_ring_count);
|
|
|
|
|
|
- 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);
|
|
|
+ /* 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- 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);
|
|
|
+ e1000e_down(adapter);
|
|
|
|
|
|
- if (netif_running(adapter->netdev)) {
|
|
|
- /* Try to get new resources before deleting old */
|
|
|
- err = e1000e_setup_rx_resources(rx_ring);
|
|
|
+ /*
|
|
|
+ * 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_rx;
|
|
|
- err = e1000e_setup_tx_resources(tx_ring);
|
|
|
+ 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_tx;
|
|
|
+ goto err_setup_rx;
|
|
|
+ }
|
|
|
|
|
|
- /*
|
|
|
- * 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->rx_ring);
|
|
|
+ /* ...then free the old resources and copy back any new ring data */
|
|
|
+ if (set_tx) {
|
|
|
e1000e_free_tx_resources(adapter->tx_ring);
|
|
|
- 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;
|
|
|
+ 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;
|
|
|
}
|
|
|
|
|
|
- clear_bit(__E1000_RESETTING, &adapter->state);
|
|
|
- return 0;
|
|
|
-err_setup_tx:
|
|
|
- e1000e_free_rx_resources(rx_ring);
|
|
|
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);
|
|
|
+ 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;
|
|
|
}
|