/** * e1000_setup_rx_resources - allocate Rx resources (Descriptors) * * @v adapter e1000 private structure * * @ret rc Returns 0 on success, negative on failure **/ static int e1000e_setup_rx_resources ( struct e1000_adapter *adapter ) { int i, rc = 0; DBGP ( "e1000_setup_rx_resources\n" ); /* Allocate receive descriptor ring memory. It must not cross a 64K boundary because of hardware errata */ adapter->rx_base = malloc_dma ( adapter->rx_ring_size, adapter->rx_ring_size ); if ( ! adapter->rx_base ) { return -ENOMEM; } memset ( adapter->rx_base, 0, adapter->rx_ring_size ); for ( i = 0; i < NUM_RX_DESC; i++ ) { /* let e1000_refill_rx_ring() io_buffer allocations */ adapter->rx_iobuf[i] = NULL; } /* allocate io_buffers */ rc = e1000e_refill_rx_ring ( adapter ); if ( rc < 0 ) e1000e_free_rx_resources ( adapter ); return rc; }
/** * e1000_close - Disables a network interface * * @v netdev network interface device structure * **/ static void e1000e_close ( struct net_device *netdev ) { struct e1000_adapter *adapter = netdev_priv ( netdev ); struct e1000_hw *hw = &adapter->hw; uint32_t rctl; uint32_t icr; DBGP ( "e1000_close\n" ); /* Acknowledge interrupts */ icr = E1000_READ_REG ( hw, E1000_ICR ); e1000e_irq_disable ( adapter ); /* disable receives */ rctl = E1000_READ_REG ( hw, E1000_RCTL ); E1000_WRITE_REG ( hw, E1000_RCTL, rctl & ~E1000_RCTL_EN ); e1e_flush(); e1000e_reset ( adapter ); e1000e_free_tx_resources ( adapter ); e1000e_free_rx_resources ( adapter ); }
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_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; }