|
@@ -534,31 +534,27 @@ rx_ring_summary:
|
|
|
|
|
|
if (staterr & E1000_RXD_STAT_DD) {
|
|
|
/* Descriptor Done */
|
|
|
- pr_info("%s[0x%03X] %016llX %016llX -------"
|
|
|
- "--------- %p%s\n", "RWB", i,
|
|
|
+ pr_info("%s[0x%03X] %016llX %016llX ---------------- %s\n",
|
|
|
+ "RWB", i,
|
|
|
le64_to_cpu(u0->a),
|
|
|
le64_to_cpu(u0->b),
|
|
|
- buffer_info->skb, next_desc);
|
|
|
+ next_desc);
|
|
|
} else {
|
|
|
- pr_info("%s[0x%03X] %016llX %016llX %016llX"
|
|
|
- " %p%s\n", "R ", i,
|
|
|
+ pr_info("%s[0x%03X] %016llX %016llX %016llX %s\n",
|
|
|
+ "R ", i,
|
|
|
le64_to_cpu(u0->a),
|
|
|
le64_to_cpu(u0->b),
|
|
|
(u64)buffer_info->dma,
|
|
|
- buffer_info->skb, next_desc);
|
|
|
+ next_desc);
|
|
|
|
|
|
if (netif_msg_pktdata(adapter) &&
|
|
|
- buffer_info->dma && buffer_info->skb) {
|
|
|
- print_hex_dump(KERN_INFO, "",
|
|
|
- DUMP_PREFIX_ADDRESS,
|
|
|
- 16, 1, buffer_info->skb->data,
|
|
|
- IGB_RX_HDR_LEN, true);
|
|
|
+ buffer_info->dma && buffer_info->page) {
|
|
|
print_hex_dump(KERN_INFO, "",
|
|
|
DUMP_PREFIX_ADDRESS,
|
|
|
16, 1,
|
|
|
page_address(buffer_info->page) +
|
|
|
buffer_info->page_offset,
|
|
|
- PAGE_SIZE/2, true);
|
|
|
+ IGB_RX_BUFSZ, true);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -656,80 +652,6 @@ static void igb_cache_ring_register(struct igb_adapter *adapter)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void igb_free_queues(struct igb_adapter *adapter)
|
|
|
-{
|
|
|
- int i;
|
|
|
-
|
|
|
- for (i = 0; i < adapter->num_tx_queues; i++) {
|
|
|
- kfree(adapter->tx_ring[i]);
|
|
|
- adapter->tx_ring[i] = NULL;
|
|
|
- }
|
|
|
- for (i = 0; i < adapter->num_rx_queues; i++) {
|
|
|
- kfree(adapter->rx_ring[i]);
|
|
|
- adapter->rx_ring[i] = NULL;
|
|
|
- }
|
|
|
- adapter->num_rx_queues = 0;
|
|
|
- adapter->num_tx_queues = 0;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * igb_alloc_queues - Allocate memory for all rings
|
|
|
- * @adapter: board private structure to initialize
|
|
|
- *
|
|
|
- * We allocate one ring per queue at run-time since we don't know the
|
|
|
- * number of queues at compile-time.
|
|
|
- **/
|
|
|
-static int igb_alloc_queues(struct igb_adapter *adapter)
|
|
|
-{
|
|
|
- struct igb_ring *ring;
|
|
|
- int i;
|
|
|
-
|
|
|
- for (i = 0; i < adapter->num_tx_queues; i++) {
|
|
|
- ring = kzalloc(sizeof(struct igb_ring), GFP_KERNEL);
|
|
|
- if (!ring)
|
|
|
- goto err;
|
|
|
- ring->count = adapter->tx_ring_count;
|
|
|
- ring->queue_index = i;
|
|
|
- ring->dev = &adapter->pdev->dev;
|
|
|
- ring->netdev = adapter->netdev;
|
|
|
- /* For 82575, context index must be unique per ring. */
|
|
|
- if (adapter->hw.mac.type == e1000_82575)
|
|
|
- set_bit(IGB_RING_FLAG_TX_CTX_IDX, &ring->flags);
|
|
|
- adapter->tx_ring[i] = ring;
|
|
|
- }
|
|
|
-
|
|
|
- for (i = 0; i < adapter->num_rx_queues; i++) {
|
|
|
- ring = kzalloc(sizeof(struct igb_ring), GFP_KERNEL);
|
|
|
- if (!ring)
|
|
|
- goto err;
|
|
|
- ring->count = adapter->rx_ring_count;
|
|
|
- ring->queue_index = i;
|
|
|
- ring->dev = &adapter->pdev->dev;
|
|
|
- ring->netdev = adapter->netdev;
|
|
|
- /* set flag indicating ring supports SCTP checksum offload */
|
|
|
- if (adapter->hw.mac.type >= e1000_82576)
|
|
|
- set_bit(IGB_RING_FLAG_RX_SCTP_CSUM, &ring->flags);
|
|
|
-
|
|
|
- /*
|
|
|
- * On i350, i210, and i211, loopback VLAN packets
|
|
|
- * have the tag byte-swapped.
|
|
|
- * */
|
|
|
- if (adapter->hw.mac.type >= e1000_i350)
|
|
|
- set_bit(IGB_RING_FLAG_RX_LB_VLAN_BSWAP, &ring->flags);
|
|
|
-
|
|
|
- adapter->rx_ring[i] = ring;
|
|
|
- }
|
|
|
-
|
|
|
- igb_cache_ring_register(adapter);
|
|
|
-
|
|
|
- return 0;
|
|
|
-
|
|
|
-err:
|
|
|
- igb_free_queues(adapter);
|
|
|
-
|
|
|
- return -ENOMEM;
|
|
|
-}
|
|
|
-
|
|
|
/**
|
|
|
* igb_write_ivar - configure ivar for given MSI-X vector
|
|
|
* @hw: pointer to the HW structure
|
|
@@ -959,6 +881,35 @@ static void igb_reset_interrupt_capability(struct igb_adapter *adapter)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * igb_free_q_vector - Free memory allocated for specific interrupt vector
|
|
|
+ * @adapter: board private structure to initialize
|
|
|
+ * @v_idx: Index of vector to be freed
|
|
|
+ *
|
|
|
+ * This function frees the memory allocated to the q_vector. In addition if
|
|
|
+ * NAPI is enabled it will delete any references to the NAPI struct prior
|
|
|
+ * to freeing the q_vector.
|
|
|
+ **/
|
|
|
+static void igb_free_q_vector(struct igb_adapter *adapter, int v_idx)
|
|
|
+{
|
|
|
+ struct igb_q_vector *q_vector = adapter->q_vector[v_idx];
|
|
|
+
|
|
|
+ if (q_vector->tx.ring)
|
|
|
+ adapter->tx_ring[q_vector->tx.ring->queue_index] = NULL;
|
|
|
+
|
|
|
+ if (q_vector->rx.ring)
|
|
|
+ adapter->tx_ring[q_vector->rx.ring->queue_index] = NULL;
|
|
|
+
|
|
|
+ adapter->q_vector[v_idx] = NULL;
|
|
|
+ netif_napi_del(&q_vector->napi);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * ixgbe_get_stats64() might access the rings on this vector,
|
|
|
+ * we must wait a grace period before freeing it.
|
|
|
+ */
|
|
|
+ kfree_rcu(q_vector, rcu);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* igb_free_q_vectors - Free memory allocated for interrupt vectors
|
|
|
* @adapter: board private structure to initialize
|
|
@@ -969,17 +920,14 @@ static void igb_reset_interrupt_capability(struct igb_adapter *adapter)
|
|
|
**/
|
|
|
static void igb_free_q_vectors(struct igb_adapter *adapter)
|
|
|
{
|
|
|
- int v_idx;
|
|
|
+ int v_idx = adapter->num_q_vectors;
|
|
|
|
|
|
- for (v_idx = 0; v_idx < adapter->num_q_vectors; v_idx++) {
|
|
|
- struct igb_q_vector *q_vector = adapter->q_vector[v_idx];
|
|
|
- adapter->q_vector[v_idx] = NULL;
|
|
|
- if (!q_vector)
|
|
|
- continue;
|
|
|
- netif_napi_del(&q_vector->napi);
|
|
|
- kfree(q_vector);
|
|
|
- }
|
|
|
+ adapter->num_tx_queues = 0;
|
|
|
+ adapter->num_rx_queues = 0;
|
|
|
adapter->num_q_vectors = 0;
|
|
|
+
|
|
|
+ while (v_idx--)
|
|
|
+ igb_free_q_vector(adapter, v_idx);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -990,7 +938,6 @@ static void igb_free_q_vectors(struct igb_adapter *adapter)
|
|
|
*/
|
|
|
static void igb_clear_interrupt_scheme(struct igb_adapter *adapter)
|
|
|
{
|
|
|
- igb_free_queues(adapter);
|
|
|
igb_free_q_vectors(adapter);
|
|
|
igb_reset_interrupt_capability(adapter);
|
|
|
}
|
|
@@ -1001,7 +948,7 @@ static void igb_clear_interrupt_scheme(struct igb_adapter *adapter)
|
|
|
* Attempt to configure interrupts using the best available
|
|
|
* capabilities of the hardware and kernel.
|
|
|
**/
|
|
|
-static int igb_set_interrupt_capability(struct igb_adapter *adapter)
|
|
|
+static void igb_set_interrupt_capability(struct igb_adapter *adapter)
|
|
|
{
|
|
|
int err;
|
|
|
int numvecs, i;
|
|
@@ -1038,7 +985,7 @@ static int igb_set_interrupt_capability(struct igb_adapter *adapter)
|
|
|
adapter->msix_entries,
|
|
|
numvecs);
|
|
|
if (err == 0)
|
|
|
- goto out;
|
|
|
+ return;
|
|
|
|
|
|
igb_reset_interrupt_capability(adapter);
|
|
|
|
|
@@ -1068,105 +1015,183 @@ msi_only:
|
|
|
adapter->num_q_vectors = 1;
|
|
|
if (!pci_enable_msi(adapter->pdev))
|
|
|
adapter->flags |= IGB_FLAG_HAS_MSI;
|
|
|
-out:
|
|
|
- /* Notify the stack of the (possibly) reduced queue counts. */
|
|
|
- rtnl_lock();
|
|
|
- netif_set_real_num_tx_queues(adapter->netdev, adapter->num_tx_queues);
|
|
|
- err = netif_set_real_num_rx_queues(adapter->netdev,
|
|
|
- adapter->num_rx_queues);
|
|
|
- rtnl_unlock();
|
|
|
- return err;
|
|
|
+}
|
|
|
+
|
|
|
+static void igb_add_ring(struct igb_ring *ring,
|
|
|
+ struct igb_ring_container *head)
|
|
|
+{
|
|
|
+ head->ring = ring;
|
|
|
+ head->count++;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * igb_alloc_q_vectors - Allocate memory for interrupt vectors
|
|
|
+ * igb_alloc_q_vector - Allocate memory for a single interrupt vector
|
|
|
* @adapter: board private structure to initialize
|
|
|
+ * @v_count: q_vectors allocated on adapter, used for ring interleaving
|
|
|
+ * @v_idx: index of vector in adapter struct
|
|
|
+ * @txr_count: total number of Tx rings to allocate
|
|
|
+ * @txr_idx: index of first Tx ring to allocate
|
|
|
+ * @rxr_count: total number of Rx rings to allocate
|
|
|
+ * @rxr_idx: index of first Rx ring to allocate
|
|
|
*
|
|
|
- * We allocate one q_vector per queue interrupt. If allocation fails we
|
|
|
- * return -ENOMEM.
|
|
|
+ * We allocate one q_vector. If allocation fails we return -ENOMEM.
|
|
|
**/
|
|
|
-static int igb_alloc_q_vectors(struct igb_adapter *adapter)
|
|
|
+static int igb_alloc_q_vector(struct igb_adapter *adapter,
|
|
|
+ int v_count, int v_idx,
|
|
|
+ int txr_count, int txr_idx,
|
|
|
+ int rxr_count, int rxr_idx)
|
|
|
{
|
|
|
struct igb_q_vector *q_vector;
|
|
|
- struct e1000_hw *hw = &adapter->hw;
|
|
|
- int v_idx;
|
|
|
+ struct igb_ring *ring;
|
|
|
+ int ring_count, size;
|
|
|
|
|
|
- for (v_idx = 0; v_idx < adapter->num_q_vectors; v_idx++) {
|
|
|
- q_vector = kzalloc(sizeof(struct igb_q_vector),
|
|
|
- GFP_KERNEL);
|
|
|
- if (!q_vector)
|
|
|
- goto err_out;
|
|
|
- q_vector->adapter = adapter;
|
|
|
- q_vector->itr_register = hw->hw_addr + E1000_EITR(0);
|
|
|
- q_vector->itr_val = IGB_START_ITR;
|
|
|
- netif_napi_add(adapter->netdev, &q_vector->napi, igb_poll, 64);
|
|
|
- adapter->q_vector[v_idx] = q_vector;
|
|
|
+ /* igb only supports 1 Tx and/or 1 Rx queue per vector */
|
|
|
+ if (txr_count > 1 || rxr_count > 1)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ ring_count = txr_count + rxr_count;
|
|
|
+ size = sizeof(struct igb_q_vector) +
|
|
|
+ (sizeof(struct igb_ring) * ring_count);
|
|
|
+
|
|
|
+ /* allocate q_vector and rings */
|
|
|
+ q_vector = kzalloc(size, GFP_KERNEL);
|
|
|
+ if (!q_vector)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ /* initialize NAPI */
|
|
|
+ netif_napi_add(adapter->netdev, &q_vector->napi,
|
|
|
+ igb_poll, 64);
|
|
|
+
|
|
|
+ /* tie q_vector and adapter together */
|
|
|
+ adapter->q_vector[v_idx] = q_vector;
|
|
|
+ q_vector->adapter = adapter;
|
|
|
+
|
|
|
+ /* initialize work limits */
|
|
|
+ q_vector->tx.work_limit = adapter->tx_work_limit;
|
|
|
+
|
|
|
+ /* initialize ITR configuration */
|
|
|
+ q_vector->itr_register = adapter->hw.hw_addr + E1000_EITR(0);
|
|
|
+ q_vector->itr_val = IGB_START_ITR;
|
|
|
+
|
|
|
+ /* initialize pointer to rings */
|
|
|
+ ring = q_vector->ring;
|
|
|
+
|
|
|
+ if (txr_count) {
|
|
|
+ /* assign generic ring traits */
|
|
|
+ ring->dev = &adapter->pdev->dev;
|
|
|
+ ring->netdev = adapter->netdev;
|
|
|
+
|
|
|
+ /* configure backlink on ring */
|
|
|
+ ring->q_vector = q_vector;
|
|
|
+
|
|
|
+ /* update q_vector Tx values */
|
|
|
+ igb_add_ring(ring, &q_vector->tx);
|
|
|
+
|
|
|
+ /* For 82575, context index must be unique per ring. */
|
|
|
+ if (adapter->hw.mac.type == e1000_82575)
|
|
|
+ set_bit(IGB_RING_FLAG_TX_CTX_IDX, &ring->flags);
|
|
|
+
|
|
|
+ /* apply Tx specific ring traits */
|
|
|
+ ring->count = adapter->tx_ring_count;
|
|
|
+ ring->queue_index = txr_idx;
|
|
|
+
|
|
|
+ /* assign ring to adapter */
|
|
|
+ adapter->tx_ring[txr_idx] = ring;
|
|
|
+
|
|
|
+ /* push pointer to next ring */
|
|
|
+ ring++;
|
|
|
}
|
|
|
|
|
|
- return 0;
|
|
|
+ if (rxr_count) {
|
|
|
+ /* assign generic ring traits */
|
|
|
+ ring->dev = &adapter->pdev->dev;
|
|
|
+ ring->netdev = adapter->netdev;
|
|
|
|
|
|
-err_out:
|
|
|
- igb_free_q_vectors(adapter);
|
|
|
- return -ENOMEM;
|
|
|
-}
|
|
|
+ /* configure backlink on ring */
|
|
|
+ ring->q_vector = q_vector;
|
|
|
|
|
|
-static void igb_map_rx_ring_to_vector(struct igb_adapter *adapter,
|
|
|
- int ring_idx, int v_idx)
|
|
|
-{
|
|
|
- struct igb_q_vector *q_vector = adapter->q_vector[v_idx];
|
|
|
+ /* update q_vector Rx values */
|
|
|
+ igb_add_ring(ring, &q_vector->rx);
|
|
|
|
|
|
- q_vector->rx.ring = adapter->rx_ring[ring_idx];
|
|
|
- q_vector->rx.ring->q_vector = q_vector;
|
|
|
- q_vector->rx.count++;
|
|
|
- q_vector->itr_val = adapter->rx_itr_setting;
|
|
|
- if (q_vector->itr_val && q_vector->itr_val <= 3)
|
|
|
- q_vector->itr_val = IGB_START_ITR;
|
|
|
-}
|
|
|
+ /* set flag indicating ring supports SCTP checksum offload */
|
|
|
+ if (adapter->hw.mac.type >= e1000_82576)
|
|
|
+ set_bit(IGB_RING_FLAG_RX_SCTP_CSUM, &ring->flags);
|
|
|
|
|
|
-static void igb_map_tx_ring_to_vector(struct igb_adapter *adapter,
|
|
|
- int ring_idx, int v_idx)
|
|
|
-{
|
|
|
- struct igb_q_vector *q_vector = adapter->q_vector[v_idx];
|
|
|
+ /*
|
|
|
+ * On i350, i210, and i211, loopback VLAN packets
|
|
|
+ * have the tag byte-swapped.
|
|
|
+ * */
|
|
|
+ if (adapter->hw.mac.type >= e1000_i350)
|
|
|
+ set_bit(IGB_RING_FLAG_RX_LB_VLAN_BSWAP, &ring->flags);
|
|
|
|
|
|
- q_vector->tx.ring = adapter->tx_ring[ring_idx];
|
|
|
- q_vector->tx.ring->q_vector = q_vector;
|
|
|
- q_vector->tx.count++;
|
|
|
- q_vector->itr_val = adapter->tx_itr_setting;
|
|
|
- q_vector->tx.work_limit = adapter->tx_work_limit;
|
|
|
- if (q_vector->itr_val && q_vector->itr_val <= 3)
|
|
|
- q_vector->itr_val = IGB_START_ITR;
|
|
|
+ /* apply Rx specific ring traits */
|
|
|
+ ring->count = adapter->rx_ring_count;
|
|
|
+ ring->queue_index = rxr_idx;
|
|
|
+
|
|
|
+ /* assign ring to adapter */
|
|
|
+ adapter->rx_ring[rxr_idx] = ring;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
/**
|
|
|
- * igb_map_ring_to_vector - maps allocated queues to vectors
|
|
|
+ * igb_alloc_q_vectors - Allocate memory for interrupt vectors
|
|
|
+ * @adapter: board private structure to initialize
|
|
|
*
|
|
|
- * This function maps the recently allocated queues to vectors.
|
|
|
+ * We allocate one q_vector per queue interrupt. If allocation fails we
|
|
|
+ * return -ENOMEM.
|
|
|
**/
|
|
|
-static int igb_map_ring_to_vector(struct igb_adapter *adapter)
|
|
|
+static int igb_alloc_q_vectors(struct igb_adapter *adapter)
|
|
|
{
|
|
|
- int i;
|
|
|
- int v_idx = 0;
|
|
|
+ int q_vectors = adapter->num_q_vectors;
|
|
|
+ int rxr_remaining = adapter->num_rx_queues;
|
|
|
+ int txr_remaining = adapter->num_tx_queues;
|
|
|
+ int rxr_idx = 0, txr_idx = 0, v_idx = 0;
|
|
|
+ int err;
|
|
|
|
|
|
- if ((adapter->num_q_vectors < adapter->num_rx_queues) ||
|
|
|
- (adapter->num_q_vectors < adapter->num_tx_queues))
|
|
|
- return -ENOMEM;
|
|
|
+ if (q_vectors >= (rxr_remaining + txr_remaining)) {
|
|
|
+ for (; rxr_remaining; v_idx++) {
|
|
|
+ err = igb_alloc_q_vector(adapter, q_vectors, v_idx,
|
|
|
+ 0, 0, 1, rxr_idx);
|
|
|
|
|
|
- if (adapter->num_q_vectors >=
|
|
|
- (adapter->num_rx_queues + adapter->num_tx_queues)) {
|
|
|
- for (i = 0; i < adapter->num_rx_queues; i++)
|
|
|
- igb_map_rx_ring_to_vector(adapter, i, v_idx++);
|
|
|
- for (i = 0; i < adapter->num_tx_queues; i++)
|
|
|
- igb_map_tx_ring_to_vector(adapter, i, v_idx++);
|
|
|
- } else {
|
|
|
- for (i = 0; i < adapter->num_rx_queues; i++) {
|
|
|
- if (i < adapter->num_tx_queues)
|
|
|
- igb_map_tx_ring_to_vector(adapter, i, v_idx);
|
|
|
- igb_map_rx_ring_to_vector(adapter, i, v_idx++);
|
|
|
+ if (err)
|
|
|
+ goto err_out;
|
|
|
+
|
|
|
+ /* update counts and index */
|
|
|
+ rxr_remaining--;
|
|
|
+ rxr_idx++;
|
|
|
}
|
|
|
- for (; i < adapter->num_tx_queues; i++)
|
|
|
- igb_map_tx_ring_to_vector(adapter, i, v_idx++);
|
|
|
}
|
|
|
+
|
|
|
+ for (; v_idx < q_vectors; v_idx++) {
|
|
|
+ int rqpv = DIV_ROUND_UP(rxr_remaining, q_vectors - v_idx);
|
|
|
+ int tqpv = DIV_ROUND_UP(txr_remaining, q_vectors - v_idx);
|
|
|
+ err = igb_alloc_q_vector(adapter, q_vectors, v_idx,
|
|
|
+ tqpv, txr_idx, rqpv, rxr_idx);
|
|
|
+
|
|
|
+ if (err)
|
|
|
+ goto err_out;
|
|
|
+
|
|
|
+ /* update counts and index */
|
|
|
+ rxr_remaining -= rqpv;
|
|
|
+ txr_remaining -= tqpv;
|
|
|
+ rxr_idx++;
|
|
|
+ txr_idx++;
|
|
|
+ }
|
|
|
+
|
|
|
return 0;
|
|
|
+
|
|
|
+err_out:
|
|
|
+ adapter->num_tx_queues = 0;
|
|
|
+ adapter->num_rx_queues = 0;
|
|
|
+ adapter->num_q_vectors = 0;
|
|
|
+
|
|
|
+ while (v_idx--)
|
|
|
+ igb_free_q_vector(adapter, v_idx);
|
|
|
+
|
|
|
+ return -ENOMEM;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1179,9 +1204,7 @@ static int igb_init_interrupt_scheme(struct igb_adapter *adapter)
|
|
|
struct pci_dev *pdev = adapter->pdev;
|
|
|
int err;
|
|
|
|
|
|
- err = igb_set_interrupt_capability(adapter);
|
|
|
- if (err)
|
|
|
- return err;
|
|
|
+ igb_set_interrupt_capability(adapter);
|
|
|
|
|
|
err = igb_alloc_q_vectors(adapter);
|
|
|
if (err) {
|
|
@@ -1189,24 +1212,10 @@ static int igb_init_interrupt_scheme(struct igb_adapter *adapter)
|
|
|
goto err_alloc_q_vectors;
|
|
|
}
|
|
|
|
|
|
- err = igb_alloc_queues(adapter);
|
|
|
- if (err) {
|
|
|
- dev_err(&pdev->dev, "Unable to allocate memory for queues\n");
|
|
|
- goto err_alloc_queues;
|
|
|
- }
|
|
|
-
|
|
|
- err = igb_map_ring_to_vector(adapter);
|
|
|
- if (err) {
|
|
|
- dev_err(&pdev->dev, "Invalid q_vector to ring mapping\n");
|
|
|
- goto err_map_queues;
|
|
|
- }
|
|
|
-
|
|
|
+ igb_cache_ring_register(adapter);
|
|
|
|
|
|
return 0;
|
|
|
-err_map_queues:
|
|
|
- igb_free_queues(adapter);
|
|
|
-err_alloc_queues:
|
|
|
- igb_free_q_vectors(adapter);
|
|
|
+
|
|
|
err_alloc_q_vectors:
|
|
|
igb_reset_interrupt_capability(adapter);
|
|
|
return err;
|
|
@@ -1229,11 +1238,11 @@ static int igb_request_irq(struct igb_adapter *adapter)
|
|
|
if (!err)
|
|
|
goto request_done;
|
|
|
/* fall back to MSI */
|
|
|
+ igb_free_all_tx_resources(adapter);
|
|
|
+ igb_free_all_rx_resources(adapter);
|
|
|
igb_clear_interrupt_scheme(adapter);
|
|
|
if (!pci_enable_msi(pdev))
|
|
|
adapter->flags |= IGB_FLAG_HAS_MSI;
|
|
|
- igb_free_all_tx_resources(adapter);
|
|
|
- igb_free_all_rx_resources(adapter);
|
|
|
adapter->num_tx_queues = 1;
|
|
|
adapter->num_rx_queues = 1;
|
|
|
adapter->num_q_vectors = 1;
|
|
@@ -1243,13 +1252,6 @@ static int igb_request_irq(struct igb_adapter *adapter)
|
|
|
"Unable to allocate memory for vectors\n");
|
|
|
goto request_done;
|
|
|
}
|
|
|
- err = igb_alloc_queues(adapter);
|
|
|
- if (err) {
|
|
|
- dev_err(&pdev->dev,
|
|
|
- "Unable to allocate memory for queues\n");
|
|
|
- igb_free_q_vectors(adapter);
|
|
|
- goto request_done;
|
|
|
- }
|
|
|
igb_setup_all_tx_resources(adapter);
|
|
|
igb_setup_all_rx_resources(adapter);
|
|
|
}
|
|
@@ -2531,6 +2533,17 @@ static int __igb_open(struct net_device *netdev, bool resuming)
|
|
|
if (err)
|
|
|
goto err_req_irq;
|
|
|
|
|
|
+ /* Notify the stack of the actual queue counts. */
|
|
|
+ err = netif_set_real_num_tx_queues(adapter->netdev,
|
|
|
+ adapter->num_tx_queues);
|
|
|
+ if (err)
|
|
|
+ goto err_set_queues;
|
|
|
+
|
|
|
+ err = netif_set_real_num_rx_queues(adapter->netdev,
|
|
|
+ adapter->num_rx_queues);
|
|
|
+ if (err)
|
|
|
+ goto err_set_queues;
|
|
|
+
|
|
|
/* From here on the code is the same as igb_up() */
|
|
|
clear_bit(__IGB_DOWN, &adapter->state);
|
|
|
|
|
@@ -2560,6 +2573,8 @@ static int __igb_open(struct net_device *netdev, bool resuming)
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
+err_set_queues:
|
|
|
+ igb_free_irq(adapter);
|
|
|
err_req_irq:
|
|
|
igb_release_hw_control(adapter);
|
|
|
igb_power_down_link(adapter);
|
|
@@ -2637,10 +2652,8 @@ int igb_setup_tx_resources(struct igb_ring *tx_ring)
|
|
|
tx_ring->size = tx_ring->count * sizeof(union e1000_adv_tx_desc);
|
|
|
tx_ring->size = ALIGN(tx_ring->size, 4096);
|
|
|
|
|
|
- tx_ring->desc = dma_alloc_coherent(dev,
|
|
|
- tx_ring->size,
|
|
|
- &tx_ring->dma,
|
|
|
- GFP_KERNEL);
|
|
|
+ tx_ring->desc = dma_alloc_coherent(dev, tx_ring->size,
|
|
|
+ &tx_ring->dma, GFP_KERNEL);
|
|
|
if (!tx_ring->desc)
|
|
|
goto err;
|
|
|
|
|
@@ -2777,18 +2790,16 @@ int igb_setup_rx_resources(struct igb_ring *rx_ring)
|
|
|
if (!rx_ring->rx_buffer_info)
|
|
|
goto err;
|
|
|
|
|
|
-
|
|
|
/* Round up to nearest 4K */
|
|
|
rx_ring->size = rx_ring->count * sizeof(union e1000_adv_rx_desc);
|
|
|
rx_ring->size = ALIGN(rx_ring->size, 4096);
|
|
|
|
|
|
- rx_ring->desc = dma_alloc_coherent(dev,
|
|
|
- rx_ring->size,
|
|
|
- &rx_ring->dma,
|
|
|
- GFP_KERNEL);
|
|
|
+ rx_ring->desc = dma_alloc_coherent(dev, rx_ring->size,
|
|
|
+ &rx_ring->dma, GFP_KERNEL);
|
|
|
if (!rx_ring->desc)
|
|
|
goto err;
|
|
|
|
|
|
+ rx_ring->next_to_alloc = 0;
|
|
|
rx_ring->next_to_clean = 0;
|
|
|
rx_ring->next_to_use = 0;
|
|
|
|
|
@@ -3106,12 +3117,8 @@ void igb_configure_rx_ring(struct igb_adapter *adapter,
|
|
|
|
|
|
/* set descriptor configuration */
|
|
|
srrctl = IGB_RX_HDR_LEN << E1000_SRRCTL_BSIZEHDRSIZE_SHIFT;
|
|
|
-#if (PAGE_SIZE / 2) > IGB_RXBUFFER_16384
|
|
|
- srrctl |= IGB_RXBUFFER_16384 >> E1000_SRRCTL_BSIZEPKT_SHIFT;
|
|
|
-#else
|
|
|
- srrctl |= (PAGE_SIZE / 2) >> E1000_SRRCTL_BSIZEPKT_SHIFT;
|
|
|
-#endif
|
|
|
- srrctl |= E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS;
|
|
|
+ srrctl |= IGB_RX_BUFSZ >> E1000_SRRCTL_BSIZEPKT_SHIFT;
|
|
|
+ srrctl |= E1000_SRRCTL_DESCTYPE_ADV_ONEBUF;
|
|
|
#ifdef CONFIG_IGB_PTP
|
|
|
if (hw->mac.type >= e1000_82580)
|
|
|
srrctl |= E1000_SRRCTL_TIMESTAMP;
|
|
@@ -3305,36 +3312,27 @@ static void igb_clean_rx_ring(struct igb_ring *rx_ring)
|
|
|
unsigned long size;
|
|
|
u16 i;
|
|
|
|
|
|
+ if (rx_ring->skb)
|
|
|
+ dev_kfree_skb(rx_ring->skb);
|
|
|
+ rx_ring->skb = NULL;
|
|
|
+
|
|
|
if (!rx_ring->rx_buffer_info)
|
|
|
return;
|
|
|
|
|
|
/* Free all the Rx ring sk_buffs */
|
|
|
for (i = 0; i < rx_ring->count; i++) {
|
|
|
struct igb_rx_buffer *buffer_info = &rx_ring->rx_buffer_info[i];
|
|
|
- if (buffer_info->dma) {
|
|
|
- dma_unmap_single(rx_ring->dev,
|
|
|
- buffer_info->dma,
|
|
|
- IGB_RX_HDR_LEN,
|
|
|
- DMA_FROM_DEVICE);
|
|
|
- buffer_info->dma = 0;
|
|
|
- }
|
|
|
|
|
|
- if (buffer_info->skb) {
|
|
|
- dev_kfree_skb(buffer_info->skb);
|
|
|
- buffer_info->skb = NULL;
|
|
|
- }
|
|
|
- if (buffer_info->page_dma) {
|
|
|
- dma_unmap_page(rx_ring->dev,
|
|
|
- buffer_info->page_dma,
|
|
|
- PAGE_SIZE / 2,
|
|
|
- DMA_FROM_DEVICE);
|
|
|
- buffer_info->page_dma = 0;
|
|
|
- }
|
|
|
- if (buffer_info->page) {
|
|
|
- put_page(buffer_info->page);
|
|
|
- buffer_info->page = NULL;
|
|
|
- buffer_info->page_offset = 0;
|
|
|
- }
|
|
|
+ if (!buffer_info->page)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ dma_unmap_page(rx_ring->dev,
|
|
|
+ buffer_info->dma,
|
|
|
+ PAGE_SIZE,
|
|
|
+ DMA_FROM_DEVICE);
|
|
|
+ __free_page(buffer_info->page);
|
|
|
+
|
|
|
+ buffer_info->page = NULL;
|
|
|
}
|
|
|
|
|
|
size = sizeof(struct igb_rx_buffer) * rx_ring->count;
|
|
@@ -3343,6 +3341,7 @@ static void igb_clean_rx_ring(struct igb_ring *rx_ring)
|
|
|
/* Zero out the descriptor ring */
|
|
|
memset(rx_ring->desc, 0, rx_ring->size);
|
|
|
|
|
|
+ rx_ring->next_to_alloc = 0;
|
|
|
rx_ring->next_to_clean = 0;
|
|
|
rx_ring->next_to_use = 0;
|
|
|
}
|
|
@@ -4467,10 +4466,11 @@ static netdev_tx_t igb_xmit_frame(struct sk_buff *skb,
|
|
|
* The minimum packet size with TCTL.PSP set is 17 so pad the skb
|
|
|
* in order to meet this minimum size requirement.
|
|
|
*/
|
|
|
- if (skb->len < 17) {
|
|
|
- if (skb_padto(skb, 17))
|
|
|
+ if (unlikely(skb->len < 17)) {
|
|
|
+ if (skb_pad(skb, 17 - skb->len))
|
|
|
return NETDEV_TX_OK;
|
|
|
skb->len = 17;
|
|
|
+ skb_set_tail_pointer(skb, 17);
|
|
|
}
|
|
|
|
|
|
return igb_xmit_frame_ring(skb, igb_tx_queue_mapping(adapter, skb));
|
|
@@ -4851,45 +4851,63 @@ static irqreturn_t igb_msix_ring(int irq, void *data)
|
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_IGB_DCA
|
|
|
+static void igb_update_tx_dca(struct igb_adapter *adapter,
|
|
|
+ struct igb_ring *tx_ring,
|
|
|
+ int cpu)
|
|
|
+{
|
|
|
+ struct e1000_hw *hw = &adapter->hw;
|
|
|
+ u32 txctrl = dca3_get_tag(tx_ring->dev, cpu);
|
|
|
+
|
|
|
+ if (hw->mac.type != e1000_82575)
|
|
|
+ txctrl <<= E1000_DCA_TXCTRL_CPUID_SHIFT;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * We can enable relaxed ordering for reads, but not writes when
|
|
|
+ * DCA is enabled. This is due to a known issue in some chipsets
|
|
|
+ * which will cause the DCA tag to be cleared.
|
|
|
+ */
|
|
|
+ txctrl |= E1000_DCA_TXCTRL_DESC_RRO_EN |
|
|
|
+ E1000_DCA_TXCTRL_DATA_RRO_EN |
|
|
|
+ E1000_DCA_TXCTRL_DESC_DCA_EN;
|
|
|
+
|
|
|
+ wr32(E1000_DCA_TXCTRL(tx_ring->reg_idx), txctrl);
|
|
|
+}
|
|
|
+
|
|
|
+static void igb_update_rx_dca(struct igb_adapter *adapter,
|
|
|
+ struct igb_ring *rx_ring,
|
|
|
+ int cpu)
|
|
|
+{
|
|
|
+ struct e1000_hw *hw = &adapter->hw;
|
|
|
+ u32 rxctrl = dca3_get_tag(&adapter->pdev->dev, cpu);
|
|
|
+
|
|
|
+ if (hw->mac.type != e1000_82575)
|
|
|
+ rxctrl <<= E1000_DCA_RXCTRL_CPUID_SHIFT;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * We can enable relaxed ordering for reads, but not writes when
|
|
|
+ * DCA is enabled. This is due to a known issue in some chipsets
|
|
|
+ * which will cause the DCA tag to be cleared.
|
|
|
+ */
|
|
|
+ rxctrl |= E1000_DCA_RXCTRL_DESC_RRO_EN |
|
|
|
+ E1000_DCA_RXCTRL_DESC_DCA_EN;
|
|
|
+
|
|
|
+ wr32(E1000_DCA_RXCTRL(rx_ring->reg_idx), rxctrl);
|
|
|
+}
|
|
|
+
|
|
|
static void igb_update_dca(struct igb_q_vector *q_vector)
|
|
|
{
|
|
|
struct igb_adapter *adapter = q_vector->adapter;
|
|
|
- struct e1000_hw *hw = &adapter->hw;
|
|
|
int cpu = get_cpu();
|
|
|
|
|
|
if (q_vector->cpu == cpu)
|
|
|
goto out_no_update;
|
|
|
|
|
|
- if (q_vector->tx.ring) {
|
|
|
- int q = q_vector->tx.ring->reg_idx;
|
|
|
- u32 dca_txctrl = rd32(E1000_DCA_TXCTRL(q));
|
|
|
- if (hw->mac.type == e1000_82575) {
|
|
|
- dca_txctrl &= ~E1000_DCA_TXCTRL_CPUID_MASK;
|
|
|
- dca_txctrl |= dca3_get_tag(&adapter->pdev->dev, cpu);
|
|
|
- } else {
|
|
|
- dca_txctrl &= ~E1000_DCA_TXCTRL_CPUID_MASK_82576;
|
|
|
- dca_txctrl |= dca3_get_tag(&adapter->pdev->dev, cpu) <<
|
|
|
- E1000_DCA_TXCTRL_CPUID_SHIFT;
|
|
|
- }
|
|
|
- dca_txctrl |= E1000_DCA_TXCTRL_DESC_DCA_EN;
|
|
|
- wr32(E1000_DCA_TXCTRL(q), dca_txctrl);
|
|
|
- }
|
|
|
- if (q_vector->rx.ring) {
|
|
|
- int q = q_vector->rx.ring->reg_idx;
|
|
|
- u32 dca_rxctrl = rd32(E1000_DCA_RXCTRL(q));
|
|
|
- if (hw->mac.type == e1000_82575) {
|
|
|
- dca_rxctrl &= ~E1000_DCA_RXCTRL_CPUID_MASK;
|
|
|
- dca_rxctrl |= dca3_get_tag(&adapter->pdev->dev, cpu);
|
|
|
- } else {
|
|
|
- dca_rxctrl &= ~E1000_DCA_RXCTRL_CPUID_MASK_82576;
|
|
|
- dca_rxctrl |= dca3_get_tag(&adapter->pdev->dev, cpu) <<
|
|
|
- E1000_DCA_RXCTRL_CPUID_SHIFT;
|
|
|
- }
|
|
|
- dca_rxctrl |= E1000_DCA_RXCTRL_DESC_DCA_EN;
|
|
|
- dca_rxctrl |= E1000_DCA_RXCTRL_HEAD_DCA_EN;
|
|
|
- dca_rxctrl |= E1000_DCA_RXCTRL_DATA_DCA_EN;
|
|
|
- wr32(E1000_DCA_RXCTRL(q), dca_rxctrl);
|
|
|
- }
|
|
|
+ if (q_vector->tx.ring)
|
|
|
+ igb_update_tx_dca(adapter, q_vector->tx.ring, cpu);
|
|
|
+
|
|
|
+ if (q_vector->rx.ring)
|
|
|
+ igb_update_rx_dca(adapter, q_vector->rx.ring, cpu);
|
|
|
+
|
|
|
q_vector->cpu = cpu;
|
|
|
out_no_update:
|
|
|
put_cpu();
|
|
@@ -5840,6 +5858,183 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
|
|
|
return !!budget;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * igb_reuse_rx_page - page flip buffer and store it back on the ring
|
|
|
+ * @rx_ring: rx descriptor ring to store buffers on
|
|
|
+ * @old_buff: donor buffer to have page reused
|
|
|
+ *
|
|
|
+ * Synchronizes page for reuse by the adapter
|
|
|
+ **/
|
|
|
+static void igb_reuse_rx_page(struct igb_ring *rx_ring,
|
|
|
+ struct igb_rx_buffer *old_buff)
|
|
|
+{
|
|
|
+ struct igb_rx_buffer *new_buff;
|
|
|
+ u16 nta = rx_ring->next_to_alloc;
|
|
|
+
|
|
|
+ new_buff = &rx_ring->rx_buffer_info[nta];
|
|
|
+
|
|
|
+ /* update, and store next to alloc */
|
|
|
+ nta++;
|
|
|
+ rx_ring->next_to_alloc = (nta < rx_ring->count) ? nta : 0;
|
|
|
+
|
|
|
+ /* transfer page from old buffer to new buffer */
|
|
|
+ memcpy(new_buff, old_buff, sizeof(struct igb_rx_buffer));
|
|
|
+
|
|
|
+ /* sync the buffer for use by the device */
|
|
|
+ dma_sync_single_range_for_device(rx_ring->dev, old_buff->dma,
|
|
|
+ old_buff->page_offset,
|
|
|
+ IGB_RX_BUFSZ,
|
|
|
+ DMA_FROM_DEVICE);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * igb_add_rx_frag - Add contents of Rx buffer to sk_buff
|
|
|
+ * @rx_ring: rx descriptor ring to transact packets on
|
|
|
+ * @rx_buffer: buffer containing page to add
|
|
|
+ * @rx_desc: descriptor containing length of buffer written by hardware
|
|
|
+ * @skb: sk_buff to place the data into
|
|
|
+ *
|
|
|
+ * This function will add the data contained in rx_buffer->page to the skb.
|
|
|
+ * This is done either through a direct copy if the data in the buffer is
|
|
|
+ * less than the skb header size, otherwise it will just attach the page as
|
|
|
+ * a frag to the skb.
|
|
|
+ *
|
|
|
+ * The function will then update the page offset if necessary and return
|
|
|
+ * true if the buffer can be reused by the adapter.
|
|
|
+ **/
|
|
|
+static bool igb_add_rx_frag(struct igb_ring *rx_ring,
|
|
|
+ struct igb_rx_buffer *rx_buffer,
|
|
|
+ union e1000_adv_rx_desc *rx_desc,
|
|
|
+ struct sk_buff *skb)
|
|
|
+{
|
|
|
+ struct page *page = rx_buffer->page;
|
|
|
+ unsigned int size = le16_to_cpu(rx_desc->wb.upper.length);
|
|
|
+
|
|
|
+ if ((size <= IGB_RX_HDR_LEN) && !skb_is_nonlinear(skb)) {
|
|
|
+ unsigned char *va = page_address(page) + rx_buffer->page_offset;
|
|
|
+
|
|
|
+#ifdef CONFIG_IGB_PTP
|
|
|
+ if (igb_test_staterr(rx_desc, E1000_RXDADV_STAT_TSIP)) {
|
|
|
+ igb_ptp_rx_pktstamp(rx_ring->q_vector, va, skb);
|
|
|
+ va += IGB_TS_HDR_LEN;
|
|
|
+ size -= IGB_TS_HDR_LEN;
|
|
|
+ }
|
|
|
+
|
|
|
+#endif
|
|
|
+ memcpy(__skb_put(skb, size), va, ALIGN(size, sizeof(long)));
|
|
|
+
|
|
|
+ /* we can reuse buffer as-is, just make sure it is local */
|
|
|
+ if (likely(page_to_nid(page) == numa_node_id()))
|
|
|
+ return true;
|
|
|
+
|
|
|
+ /* this page cannot be reused so discard it */
|
|
|
+ put_page(page);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
|
|
|
+ rx_buffer->page_offset, size, IGB_RX_BUFSZ);
|
|
|
+
|
|
|
+ /* avoid re-using remote pages */
|
|
|
+ if (unlikely(page_to_nid(page) != numa_node_id()))
|
|
|
+ return false;
|
|
|
+
|
|
|
+#if (PAGE_SIZE < 8192)
|
|
|
+ /* if we are only owner of page we can reuse it */
|
|
|
+ if (unlikely(page_count(page) != 1))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ /* flip page offset to other buffer */
|
|
|
+ rx_buffer->page_offset ^= IGB_RX_BUFSZ;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * since we are the only owner of the page and we need to
|
|
|
+ * increment it, just set the value to 2 in order to avoid
|
|
|
+ * an unnecessary locked operation
|
|
|
+ */
|
|
|
+ atomic_set(&page->_count, 2);
|
|
|
+#else
|
|
|
+ /* move offset up to the next cache line */
|
|
|
+ rx_buffer->page_offset += SKB_DATA_ALIGN(size);
|
|
|
+
|
|
|
+ if (rx_buffer->page_offset > (PAGE_SIZE - IGB_RX_BUFSZ))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ /* bump ref count on page before it is given to the stack */
|
|
|
+ get_page(page);
|
|
|
+#endif
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+static struct sk_buff *igb_fetch_rx_buffer(struct igb_ring *rx_ring,
|
|
|
+ union e1000_adv_rx_desc *rx_desc,
|
|
|
+ struct sk_buff *skb)
|
|
|
+{
|
|
|
+ struct igb_rx_buffer *rx_buffer;
|
|
|
+ struct page *page;
|
|
|
+
|
|
|
+ rx_buffer = &rx_ring->rx_buffer_info[rx_ring->next_to_clean];
|
|
|
+
|
|
|
+ /*
|
|
|
+ * This memory barrier is needed to keep us from reading
|
|
|
+ * any other fields out of the rx_desc until we know the
|
|
|
+ * RXD_STAT_DD bit is set
|
|
|
+ */
|
|
|
+ rmb();
|
|
|
+
|
|
|
+ page = rx_buffer->page;
|
|
|
+ prefetchw(page);
|
|
|
+
|
|
|
+ if (likely(!skb)) {
|
|
|
+ void *page_addr = page_address(page) +
|
|
|
+ rx_buffer->page_offset;
|
|
|
+
|
|
|
+ /* prefetch first cache line of first page */
|
|
|
+ prefetch(page_addr);
|
|
|
+#if L1_CACHE_BYTES < 128
|
|
|
+ prefetch(page_addr + L1_CACHE_BYTES);
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* allocate a skb to store the frags */
|
|
|
+ skb = netdev_alloc_skb_ip_align(rx_ring->netdev,
|
|
|
+ IGB_RX_HDR_LEN);
|
|
|
+ if (unlikely(!skb)) {
|
|
|
+ rx_ring->rx_stats.alloc_failed++;
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * we will be copying header into skb->data in
|
|
|
+ * pskb_may_pull so it is in our interest to prefetch
|
|
|
+ * it now to avoid a possible cache miss
|
|
|
+ */
|
|
|
+ prefetchw(skb->data);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* we are reusing so sync this buffer for CPU use */
|
|
|
+ dma_sync_single_range_for_cpu(rx_ring->dev,
|
|
|
+ rx_buffer->dma,
|
|
|
+ rx_buffer->page_offset,
|
|
|
+ IGB_RX_BUFSZ,
|
|
|
+ DMA_FROM_DEVICE);
|
|
|
+
|
|
|
+ /* pull page into skb */
|
|
|
+ if (igb_add_rx_frag(rx_ring, rx_buffer, rx_desc, skb)) {
|
|
|
+ /* hand second half of page back to the ring */
|
|
|
+ igb_reuse_rx_page(rx_ring, rx_buffer);
|
|
|
+ } else {
|
|
|
+ /* we are not reusing the buffer so unmap it */
|
|
|
+ dma_unmap_page(rx_ring->dev, rx_buffer->dma,
|
|
|
+ PAGE_SIZE, DMA_FROM_DEVICE);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* clear contents of rx_buffer */
|
|
|
+ rx_buffer->page = NULL;
|
|
|
+
|
|
|
+ return skb;
|
|
|
+}
|
|
|
+
|
|
|
static inline void igb_rx_checksum(struct igb_ring *ring,
|
|
|
union e1000_adv_rx_desc *rx_desc,
|
|
|
struct sk_buff *skb)
|
|
@@ -5889,224 +6084,390 @@ static inline void igb_rx_hash(struct igb_ring *ring,
|
|
|
skb->rxhash = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss);
|
|
|
}
|
|
|
|
|
|
-static void igb_rx_vlan(struct igb_ring *ring,
|
|
|
- union e1000_adv_rx_desc *rx_desc,
|
|
|
- struct sk_buff *skb)
|
|
|
+/**
|
|
|
+ * igb_is_non_eop - process handling of non-EOP buffers
|
|
|
+ * @rx_ring: Rx ring being processed
|
|
|
+ * @rx_desc: Rx descriptor for current buffer
|
|
|
+ * @skb: current socket buffer containing buffer in progress
|
|
|
+ *
|
|
|
+ * This function updates next to clean. If the buffer is an EOP buffer
|
|
|
+ * this function exits returning false, otherwise it will place the
|
|
|
+ * sk_buff in the next buffer to be chained and return true indicating
|
|
|
+ * that this is in fact a non-EOP buffer.
|
|
|
+ **/
|
|
|
+static bool igb_is_non_eop(struct igb_ring *rx_ring,
|
|
|
+ union e1000_adv_rx_desc *rx_desc)
|
|
|
{
|
|
|
- if (igb_test_staterr(rx_desc, E1000_RXD_STAT_VP)) {
|
|
|
- u16 vid;
|
|
|
- if (igb_test_staterr(rx_desc, E1000_RXDEXT_STATERR_LB) &&
|
|
|
- test_bit(IGB_RING_FLAG_RX_LB_VLAN_BSWAP, &ring->flags))
|
|
|
- vid = be16_to_cpu(rx_desc->wb.upper.vlan);
|
|
|
- else
|
|
|
- vid = le16_to_cpu(rx_desc->wb.upper.vlan);
|
|
|
+ u32 ntc = rx_ring->next_to_clean + 1;
|
|
|
|
|
|
- __vlan_hwaccel_put_tag(skb, vid);
|
|
|
- }
|
|
|
+ /* fetch, update, and store next to clean */
|
|
|
+ ntc = (ntc < rx_ring->count) ? ntc : 0;
|
|
|
+ rx_ring->next_to_clean = ntc;
|
|
|
+
|
|
|
+ prefetch(IGB_RX_DESC(rx_ring, ntc));
|
|
|
+
|
|
|
+ if (likely(igb_test_staterr(rx_desc, E1000_RXD_STAT_EOP)))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
-static inline u16 igb_get_hlen(union e1000_adv_rx_desc *rx_desc)
|
|
|
-{
|
|
|
- /* HW will not DMA in data larger than the given buffer, even if it
|
|
|
- * parses the (NFS, of course) header to be larger. In that case, it
|
|
|
- * fills the header buffer and spills the rest into the page.
|
|
|
+/**
|
|
|
+ * igb_get_headlen - determine size of header for LRO/GRO
|
|
|
+ * @data: pointer to the start of the headers
|
|
|
+ * @max_len: total length of section to find headers in
|
|
|
+ *
|
|
|
+ * This function is meant to determine the length of headers that will
|
|
|
+ * be recognized by hardware for LRO, and GRO offloads. The main
|
|
|
+ * motivation of doing this is to only perform one pull for IPv4 TCP
|
|
|
+ * packets so that we can do basic things like calculating the gso_size
|
|
|
+ * based on the average data per packet.
|
|
|
+ **/
|
|
|
+static unsigned int igb_get_headlen(unsigned char *data,
|
|
|
+ unsigned int max_len)
|
|
|
+{
|
|
|
+ union {
|
|
|
+ unsigned char *network;
|
|
|
+ /* l2 headers */
|
|
|
+ struct ethhdr *eth;
|
|
|
+ struct vlan_hdr *vlan;
|
|
|
+ /* l3 headers */
|
|
|
+ struct iphdr *ipv4;
|
|
|
+ struct ipv6hdr *ipv6;
|
|
|
+ } hdr;
|
|
|
+ __be16 protocol;
|
|
|
+ u8 nexthdr = 0; /* default to not TCP */
|
|
|
+ u8 hlen;
|
|
|
+
|
|
|
+ /* this should never happen, but better safe than sorry */
|
|
|
+ if (max_len < ETH_HLEN)
|
|
|
+ return max_len;
|
|
|
+
|
|
|
+ /* initialize network frame pointer */
|
|
|
+ hdr.network = data;
|
|
|
+
|
|
|
+ /* set first protocol and move network header forward */
|
|
|
+ protocol = hdr.eth->h_proto;
|
|
|
+ hdr.network += ETH_HLEN;
|
|
|
+
|
|
|
+ /* handle any vlan tag if present */
|
|
|
+ if (protocol == __constant_htons(ETH_P_8021Q)) {
|
|
|
+ if ((hdr.network - data) > (max_len - VLAN_HLEN))
|
|
|
+ return max_len;
|
|
|
+
|
|
|
+ protocol = hdr.vlan->h_vlan_encapsulated_proto;
|
|
|
+ hdr.network += VLAN_HLEN;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* handle L3 protocols */
|
|
|
+ if (protocol == __constant_htons(ETH_P_IP)) {
|
|
|
+ if ((hdr.network - data) > (max_len - sizeof(struct iphdr)))
|
|
|
+ return max_len;
|
|
|
+
|
|
|
+ /* access ihl as a u8 to avoid unaligned access on ia64 */
|
|
|
+ hlen = (hdr.network[0] & 0x0F) << 2;
|
|
|
+
|
|
|
+ /* verify hlen meets minimum size requirements */
|
|
|
+ if (hlen < sizeof(struct iphdr))
|
|
|
+ return hdr.network - data;
|
|
|
+
|
|
|
+ /* record next protocol */
|
|
|
+ nexthdr = hdr.ipv4->protocol;
|
|
|
+ hdr.network += hlen;
|
|
|
+ } else if (protocol == __constant_htons(ETH_P_IPV6)) {
|
|
|
+ if ((hdr.network - data) > (max_len - sizeof(struct ipv6hdr)))
|
|
|
+ return max_len;
|
|
|
+
|
|
|
+ /* record next protocol */
|
|
|
+ nexthdr = hdr.ipv6->nexthdr;
|
|
|
+ hdr.network += sizeof(struct ipv6hdr);
|
|
|
+ } else {
|
|
|
+ return hdr.network - data;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* finally sort out TCP */
|
|
|
+ if (nexthdr == IPPROTO_TCP) {
|
|
|
+ if ((hdr.network - data) > (max_len - sizeof(struct tcphdr)))
|
|
|
+ return max_len;
|
|
|
+
|
|
|
+ /* access doff as a u8 to avoid unaligned access on ia64 */
|
|
|
+ hlen = (hdr.network[12] & 0xF0) >> 2;
|
|
|
+
|
|
|
+ /* verify hlen meets minimum size requirements */
|
|
|
+ if (hlen < sizeof(struct tcphdr))
|
|
|
+ return hdr.network - data;
|
|
|
+
|
|
|
+ hdr.network += hlen;
|
|
|
+ } else if (nexthdr == IPPROTO_UDP) {
|
|
|
+ if ((hdr.network - data) > (max_len - sizeof(struct udphdr)))
|
|
|
+ return max_len;
|
|
|
+
|
|
|
+ hdr.network += sizeof(struct udphdr);
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If everything has gone correctly hdr.network should be the
|
|
|
+ * data section of the packet and will be the end of the header.
|
|
|
+ * If not then it probably represents the end of the last recognized
|
|
|
+ * header.
|
|
|
*/
|
|
|
- u16 hlen = (le16_to_cpu(rx_desc->wb.lower.lo_dword.hdr_info) &
|
|
|
- E1000_RXDADV_HDRBUFLEN_MASK) >> E1000_RXDADV_HDRBUFLEN_SHIFT;
|
|
|
- if (hlen > IGB_RX_HDR_LEN)
|
|
|
- hlen = IGB_RX_HDR_LEN;
|
|
|
- return hlen;
|
|
|
+ if ((hdr.network - data) < max_len)
|
|
|
+ return hdr.network - data;
|
|
|
+ else
|
|
|
+ return max_len;
|
|
|
}
|
|
|
|
|
|
-static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
|
|
|
+/**
|
|
|
+ * igb_pull_tail - igb specific version of skb_pull_tail
|
|
|
+ * @rx_ring: rx descriptor ring packet is being transacted on
|
|
|
+ * @rx_desc: pointer to the EOP Rx descriptor
|
|
|
+ * @skb: pointer to current skb being adjusted
|
|
|
+ *
|
|
|
+ * This function is an igb specific version of __pskb_pull_tail. The
|
|
|
+ * main difference between this version and the original function is that
|
|
|
+ * this function can make several assumptions about the state of things
|
|
|
+ * that allow for significant optimizations versus the standard function.
|
|
|
+ * As a result we can do things like drop a frag and maintain an accurate
|
|
|
+ * truesize for the skb.
|
|
|
+ */
|
|
|
+static void igb_pull_tail(struct igb_ring *rx_ring,
|
|
|
+ union e1000_adv_rx_desc *rx_desc,
|
|
|
+ struct sk_buff *skb)
|
|
|
{
|
|
|
- struct igb_ring *rx_ring = q_vector->rx.ring;
|
|
|
- union e1000_adv_rx_desc *rx_desc;
|
|
|
- const int current_node = numa_node_id();
|
|
|
- unsigned int total_bytes = 0, total_packets = 0;
|
|
|
- u16 cleaned_count = igb_desc_unused(rx_ring);
|
|
|
- u16 i = rx_ring->next_to_clean;
|
|
|
+ struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0];
|
|
|
+ unsigned char *va;
|
|
|
+ unsigned int pull_len;
|
|
|
|
|
|
- rx_desc = IGB_RX_DESC(rx_ring, i);
|
|
|
+ /*
|
|
|
+ * it is valid to use page_address instead of kmap since we are
|
|
|
+ * working with pages allocated out of the lomem pool per
|
|
|
+ * alloc_page(GFP_ATOMIC)
|
|
|
+ */
|
|
|
+ va = skb_frag_address(frag);
|
|
|
|
|
|
- while (igb_test_staterr(rx_desc, E1000_RXD_STAT_DD)) {
|
|
|
- struct igb_rx_buffer *buffer_info = &rx_ring->rx_buffer_info[i];
|
|
|
- struct sk_buff *skb = buffer_info->skb;
|
|
|
- union e1000_adv_rx_desc *next_rxd;
|
|
|
+#ifdef CONFIG_IGB_PTP
|
|
|
+ if (igb_test_staterr(rx_desc, E1000_RXDADV_STAT_TSIP)) {
|
|
|
+ /* retrieve timestamp from buffer */
|
|
|
+ igb_ptp_rx_pktstamp(rx_ring->q_vector, va, skb);
|
|
|
|
|
|
- buffer_info->skb = NULL;
|
|
|
- prefetch(skb->data);
|
|
|
+ /* update pointers to remove timestamp header */
|
|
|
+ skb_frag_size_sub(frag, IGB_TS_HDR_LEN);
|
|
|
+ frag->page_offset += IGB_TS_HDR_LEN;
|
|
|
+ skb->data_len -= IGB_TS_HDR_LEN;
|
|
|
+ skb->len -= IGB_TS_HDR_LEN;
|
|
|
|
|
|
- i++;
|
|
|
- if (i == rx_ring->count)
|
|
|
- i = 0;
|
|
|
+ /* move va to start of packet data */
|
|
|
+ va += IGB_TS_HDR_LEN;
|
|
|
+ }
|
|
|
|
|
|
- next_rxd = IGB_RX_DESC(rx_ring, i);
|
|
|
- prefetch(next_rxd);
|
|
|
+#endif
|
|
|
+ /*
|
|
|
+ * we need the header to contain the greater of either ETH_HLEN or
|
|
|
+ * 60 bytes if the skb->len is less than 60 for skb_pad.
|
|
|
+ */
|
|
|
+ pull_len = igb_get_headlen(va, IGB_RX_HDR_LEN);
|
|
|
|
|
|
- /*
|
|
|
- * This memory barrier is needed to keep us from reading
|
|
|
- * any other fields out of the rx_desc until we know the
|
|
|
- * RXD_STAT_DD bit is set
|
|
|
- */
|
|
|
- rmb();
|
|
|
+ /* align pull length to size of long to optimize memcpy performance */
|
|
|
+ skb_copy_to_linear_data(skb, va, ALIGN(pull_len, sizeof(long)));
|
|
|
|
|
|
- if (!skb_is_nonlinear(skb)) {
|
|
|
- __skb_put(skb, igb_get_hlen(rx_desc));
|
|
|
- dma_unmap_single(rx_ring->dev, buffer_info->dma,
|
|
|
- IGB_RX_HDR_LEN,
|
|
|
- DMA_FROM_DEVICE);
|
|
|
- buffer_info->dma = 0;
|
|
|
+ /* update all of the pointers */
|
|
|
+ skb_frag_size_sub(frag, pull_len);
|
|
|
+ frag->page_offset += pull_len;
|
|
|
+ skb->data_len -= pull_len;
|
|
|
+ skb->tail += pull_len;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * igb_cleanup_headers - Correct corrupted or empty headers
|
|
|
+ * @rx_ring: rx descriptor ring packet is being transacted on
|
|
|
+ * @rx_desc: pointer to the EOP Rx descriptor
|
|
|
+ * @skb: pointer to current skb being fixed
|
|
|
+ *
|
|
|
+ * Address the case where we are pulling data in on pages only
|
|
|
+ * and as such no data is present in the skb header.
|
|
|
+ *
|
|
|
+ * In addition if skb is not at least 60 bytes we need to pad it so that
|
|
|
+ * it is large enough to qualify as a valid Ethernet frame.
|
|
|
+ *
|
|
|
+ * Returns true if an error was encountered and skb was freed.
|
|
|
+ **/
|
|
|
+static bool igb_cleanup_headers(struct igb_ring *rx_ring,
|
|
|
+ union e1000_adv_rx_desc *rx_desc,
|
|
|
+ struct sk_buff *skb)
|
|
|
+{
|
|
|
+
|
|
|
+ if (unlikely((igb_test_staterr(rx_desc,
|
|
|
+ E1000_RXDEXT_ERR_FRAME_ERR_MASK)))) {
|
|
|
+ struct net_device *netdev = rx_ring->netdev;
|
|
|
+ if (!(netdev->features & NETIF_F_RXALL)) {
|
|
|
+ dev_kfree_skb_any(skb);
|
|
|
+ return true;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- if (rx_desc->wb.upper.length) {
|
|
|
- u16 length = le16_to_cpu(rx_desc->wb.upper.length);
|
|
|
+ /* place header in linear portion of buffer */
|
|
|
+ if (skb_is_nonlinear(skb))
|
|
|
+ igb_pull_tail(rx_ring, rx_desc, skb);
|
|
|
|
|
|
- skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags,
|
|
|
- buffer_info->page,
|
|
|
- buffer_info->page_offset,
|
|
|
- length);
|
|
|
+ /* if skb_pad returns an error the skb was freed */
|
|
|
+ if (unlikely(skb->len < 60)) {
|
|
|
+ int pad_len = 60 - skb->len;
|
|
|
|
|
|
- skb->len += length;
|
|
|
- skb->data_len += length;
|
|
|
- skb->truesize += PAGE_SIZE / 2;
|
|
|
+ if (skb_pad(skb, pad_len))
|
|
|
+ return true;
|
|
|
+ __skb_put(skb, pad_len);
|
|
|
+ }
|
|
|
|
|
|
- if ((page_count(buffer_info->page) != 1) ||
|
|
|
- (page_to_nid(buffer_info->page) != current_node))
|
|
|
- buffer_info->page = NULL;
|
|
|
- else
|
|
|
- get_page(buffer_info->page);
|
|
|
+ return false;
|
|
|
+}
|
|
|
|
|
|
- dma_unmap_page(rx_ring->dev, buffer_info->page_dma,
|
|
|
- PAGE_SIZE / 2, DMA_FROM_DEVICE);
|
|
|
- buffer_info->page_dma = 0;
|
|
|
- }
|
|
|
+/**
|
|
|
+ * igb_process_skb_fields - Populate skb header fields from Rx descriptor
|
|
|
+ * @rx_ring: rx descriptor ring packet is being transacted on
|
|
|
+ * @rx_desc: pointer to the EOP Rx descriptor
|
|
|
+ * @skb: pointer to current skb being populated
|
|
|
+ *
|
|
|
+ * This function checks the ring, descriptor, and packet information in
|
|
|
+ * order to populate the hash, checksum, VLAN, timestamp, protocol, and
|
|
|
+ * other fields within the skb.
|
|
|
+ **/
|
|
|
+static void igb_process_skb_fields(struct igb_ring *rx_ring,
|
|
|
+ union e1000_adv_rx_desc *rx_desc,
|
|
|
+ struct sk_buff *skb)
|
|
|
+{
|
|
|
+ struct net_device *dev = rx_ring->netdev;
|
|
|
|
|
|
- if (!igb_test_staterr(rx_desc, E1000_RXD_STAT_EOP)) {
|
|
|
- struct igb_rx_buffer *next_buffer;
|
|
|
- next_buffer = &rx_ring->rx_buffer_info[i];
|
|
|
- buffer_info->skb = next_buffer->skb;
|
|
|
- buffer_info->dma = next_buffer->dma;
|
|
|
- next_buffer->skb = skb;
|
|
|
- next_buffer->dma = 0;
|
|
|
- goto next_desc;
|
|
|
- }
|
|
|
+ igb_rx_hash(rx_ring, rx_desc, skb);
|
|
|
|
|
|
- if (unlikely((igb_test_staterr(rx_desc,
|
|
|
- E1000_RXDEXT_ERR_FRAME_ERR_MASK))
|
|
|
- && !(rx_ring->netdev->features & NETIF_F_RXALL))) {
|
|
|
- dev_kfree_skb_any(skb);
|
|
|
- goto next_desc;
|
|
|
- }
|
|
|
+ igb_rx_checksum(rx_ring, rx_desc, skb);
|
|
|
|
|
|
#ifdef CONFIG_IGB_PTP
|
|
|
- igb_ptp_rx_hwtstamp(q_vector, rx_desc, skb);
|
|
|
+ igb_ptp_rx_hwtstamp(rx_ring->q_vector, rx_desc, skb);
|
|
|
#endif /* CONFIG_IGB_PTP */
|
|
|
- igb_rx_hash(rx_ring, rx_desc, skb);
|
|
|
- igb_rx_checksum(rx_ring, rx_desc, skb);
|
|
|
- igb_rx_vlan(rx_ring, rx_desc, skb);
|
|
|
|
|
|
- total_bytes += skb->len;
|
|
|
- total_packets++;
|
|
|
+ if ((dev->features & NETIF_F_HW_VLAN_RX) &&
|
|
|
+ igb_test_staterr(rx_desc, E1000_RXD_STAT_VP)) {
|
|
|
+ u16 vid;
|
|
|
+ if (igb_test_staterr(rx_desc, E1000_RXDEXT_STATERR_LB) &&
|
|
|
+ test_bit(IGB_RING_FLAG_RX_LB_VLAN_BSWAP, &rx_ring->flags))
|
|
|
+ vid = be16_to_cpu(rx_desc->wb.upper.vlan);
|
|
|
+ else
|
|
|
+ vid = le16_to_cpu(rx_desc->wb.upper.vlan);
|
|
|
|
|
|
- skb->protocol = eth_type_trans(skb, rx_ring->netdev);
|
|
|
+ __vlan_hwaccel_put_tag(skb, vid);
|
|
|
+ }
|
|
|
|
|
|
- napi_gro_receive(&q_vector->napi, skb);
|
|
|
+ skb_record_rx_queue(skb, rx_ring->queue_index);
|
|
|
|
|
|
- budget--;
|
|
|
-next_desc:
|
|
|
- if (!budget)
|
|
|
- break;
|
|
|
+ skb->protocol = eth_type_trans(skb, rx_ring->netdev);
|
|
|
+}
|
|
|
+
|
|
|
+static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget)
|
|
|
+{
|
|
|
+ struct igb_ring *rx_ring = q_vector->rx.ring;
|
|
|
+ struct sk_buff *skb = rx_ring->skb;
|
|
|
+ unsigned int total_bytes = 0, total_packets = 0;
|
|
|
+ u16 cleaned_count = igb_desc_unused(rx_ring);
|
|
|
+
|
|
|
+ do {
|
|
|
+ union e1000_adv_rx_desc *rx_desc;
|
|
|
|
|
|
- cleaned_count++;
|
|
|
/* return some buffers to hardware, one at a time is too slow */
|
|
|
if (cleaned_count >= IGB_RX_BUFFER_WRITE) {
|
|
|
igb_alloc_rx_buffers(rx_ring, cleaned_count);
|
|
|
cleaned_count = 0;
|
|
|
}
|
|
|
|
|
|
- /* use prefetched values */
|
|
|
- rx_desc = next_rxd;
|
|
|
- }
|
|
|
+ rx_desc = IGB_RX_DESC(rx_ring, rx_ring->next_to_clean);
|
|
|
|
|
|
- rx_ring->next_to_clean = i;
|
|
|
- u64_stats_update_begin(&rx_ring->rx_syncp);
|
|
|
- rx_ring->rx_stats.packets += total_packets;
|
|
|
- rx_ring->rx_stats.bytes += total_bytes;
|
|
|
- u64_stats_update_end(&rx_ring->rx_syncp);
|
|
|
- q_vector->rx.total_packets += total_packets;
|
|
|
- q_vector->rx.total_bytes += total_bytes;
|
|
|
+ if (!igb_test_staterr(rx_desc, E1000_RXD_STAT_DD))
|
|
|
+ break;
|
|
|
|
|
|
- if (cleaned_count)
|
|
|
- igb_alloc_rx_buffers(rx_ring, cleaned_count);
|
|
|
+ /* retrieve a buffer from the ring */
|
|
|
+ skb = igb_fetch_rx_buffer(rx_ring, rx_desc, skb);
|
|
|
|
|
|
- return !!budget;
|
|
|
-}
|
|
|
+ /* exit if we failed to retrieve a buffer */
|
|
|
+ if (!skb)
|
|
|
+ break;
|
|
|
|
|
|
-static bool igb_alloc_mapped_skb(struct igb_ring *rx_ring,
|
|
|
- struct igb_rx_buffer *bi)
|
|
|
-{
|
|
|
- struct sk_buff *skb = bi->skb;
|
|
|
- dma_addr_t dma = bi->dma;
|
|
|
+ cleaned_count++;
|
|
|
|
|
|
- if (dma)
|
|
|
- return true;
|
|
|
+ /* fetch next buffer in frame if non-eop */
|
|
|
+ if (igb_is_non_eop(rx_ring, rx_desc))
|
|
|
+ continue;
|
|
|
|
|
|
- if (likely(!skb)) {
|
|
|
- skb = netdev_alloc_skb_ip_align(rx_ring->netdev,
|
|
|
- IGB_RX_HDR_LEN);
|
|
|
- bi->skb = skb;
|
|
|
- if (!skb) {
|
|
|
- rx_ring->rx_stats.alloc_failed++;
|
|
|
- return false;
|
|
|
+ /* verify the packet layout is correct */
|
|
|
+ if (igb_cleanup_headers(rx_ring, rx_desc, skb)) {
|
|
|
+ skb = NULL;
|
|
|
+ continue;
|
|
|
}
|
|
|
|
|
|
- /* initialize skb for ring */
|
|
|
- skb_record_rx_queue(skb, rx_ring->queue_index);
|
|
|
- }
|
|
|
+ /* probably a little skewed due to removing CRC */
|
|
|
+ total_bytes += skb->len;
|
|
|
|
|
|
- dma = dma_map_single(rx_ring->dev, skb->data,
|
|
|
- IGB_RX_HDR_LEN, DMA_FROM_DEVICE);
|
|
|
+ /* populate checksum, timestamp, VLAN, and protocol */
|
|
|
+ igb_process_skb_fields(rx_ring, rx_desc, skb);
|
|
|
|
|
|
- if (dma_mapping_error(rx_ring->dev, dma)) {
|
|
|
- rx_ring->rx_stats.alloc_failed++;
|
|
|
- return false;
|
|
|
- }
|
|
|
+ napi_gro_receive(&q_vector->napi, skb);
|
|
|
|
|
|
- bi->dma = dma;
|
|
|
- return true;
|
|
|
+ /* reset skb pointer */
|
|
|
+ skb = NULL;
|
|
|
+
|
|
|
+ /* update budget accounting */
|
|
|
+ total_packets++;
|
|
|
+ } while (likely(total_packets < budget));
|
|
|
+
|
|
|
+ /* place incomplete frames back on ring for completion */
|
|
|
+ rx_ring->skb = skb;
|
|
|
+
|
|
|
+ u64_stats_update_begin(&rx_ring->rx_syncp);
|
|
|
+ rx_ring->rx_stats.packets += total_packets;
|
|
|
+ rx_ring->rx_stats.bytes += total_bytes;
|
|
|
+ u64_stats_update_end(&rx_ring->rx_syncp);
|
|
|
+ q_vector->rx.total_packets += total_packets;
|
|
|
+ q_vector->rx.total_bytes += total_bytes;
|
|
|
+
|
|
|
+ if (cleaned_count)
|
|
|
+ igb_alloc_rx_buffers(rx_ring, cleaned_count);
|
|
|
+
|
|
|
+ return (total_packets < budget);
|
|
|
}
|
|
|
|
|
|
static bool igb_alloc_mapped_page(struct igb_ring *rx_ring,
|
|
|
struct igb_rx_buffer *bi)
|
|
|
{
|
|
|
struct page *page = bi->page;
|
|
|
- dma_addr_t page_dma = bi->page_dma;
|
|
|
- unsigned int page_offset = bi->page_offset ^ (PAGE_SIZE / 2);
|
|
|
+ dma_addr_t dma;
|
|
|
|
|
|
- if (page_dma)
|
|
|
+ /* since we are recycling buffers we should seldom need to alloc */
|
|
|
+ if (likely(page))
|
|
|
return true;
|
|
|
|
|
|
- if (!page) {
|
|
|
- page = __skb_alloc_page(GFP_ATOMIC, bi->skb);
|
|
|
- bi->page = page;
|
|
|
- if (unlikely(!page)) {
|
|
|
- rx_ring->rx_stats.alloc_failed++;
|
|
|
- return false;
|
|
|
- }
|
|
|
+ /* alloc new page for storage */
|
|
|
+ page = __skb_alloc_page(GFP_ATOMIC | __GFP_COLD, NULL);
|
|
|
+ if (unlikely(!page)) {
|
|
|
+ rx_ring->rx_stats.alloc_failed++;
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
- page_dma = dma_map_page(rx_ring->dev, page,
|
|
|
- page_offset, PAGE_SIZE / 2,
|
|
|
- DMA_FROM_DEVICE);
|
|
|
+ /* map page for use */
|
|
|
+ dma = dma_map_page(rx_ring->dev, page, 0, PAGE_SIZE, DMA_FROM_DEVICE);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * if mapping failed free memory back to system since
|
|
|
+ * there isn't much point in holding memory we can't use
|
|
|
+ */
|
|
|
+ if (dma_mapping_error(rx_ring->dev, dma)) {
|
|
|
+ __free_page(page);
|
|
|
|
|
|
- if (dma_mapping_error(rx_ring->dev, page_dma)) {
|
|
|
rx_ring->rx_stats.alloc_failed++;
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- bi->page_dma = page_dma;
|
|
|
- bi->page_offset = page_offset;
|
|
|
+ bi->dma = dma;
|
|
|
+ bi->page = page;
|
|
|
+ bi->page_offset = 0;
|
|
|
+
|
|
|
return true;
|
|
|
}
|
|
|
|
|
@@ -6120,22 +6481,23 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
|
|
|
struct igb_rx_buffer *bi;
|
|
|
u16 i = rx_ring->next_to_use;
|
|
|
|
|
|
+ /* nothing to do */
|
|
|
+ if (!cleaned_count)
|
|
|
+ return;
|
|
|
+
|
|
|
rx_desc = IGB_RX_DESC(rx_ring, i);
|
|
|
bi = &rx_ring->rx_buffer_info[i];
|
|
|
i -= rx_ring->count;
|
|
|
|
|
|
- while (cleaned_count--) {
|
|
|
- if (!igb_alloc_mapped_skb(rx_ring, bi))
|
|
|
- break;
|
|
|
-
|
|
|
- /* Refresh the desc even if buffer_addrs didn't change
|
|
|
- * because each write-back erases this info. */
|
|
|
- rx_desc->read.hdr_addr = cpu_to_le64(bi->dma);
|
|
|
-
|
|
|
+ do {
|
|
|
if (!igb_alloc_mapped_page(rx_ring, bi))
|
|
|
break;
|
|
|
|
|
|
- rx_desc->read.pkt_addr = cpu_to_le64(bi->page_dma);
|
|
|
+ /*
|
|
|
+ * Refresh the desc even if buffer_addrs didn't change
|
|
|
+ * because each write-back erases this info.
|
|
|
+ */
|
|
|
+ rx_desc->read.pkt_addr = cpu_to_le64(bi->dma + bi->page_offset);
|
|
|
|
|
|
rx_desc++;
|
|
|
bi++;
|
|
@@ -6148,17 +6510,25 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
|
|
|
|
|
|
/* clear the hdr_addr for the next_to_use descriptor */
|
|
|
rx_desc->read.hdr_addr = 0;
|
|
|
- }
|
|
|
+
|
|
|
+ cleaned_count--;
|
|
|
+ } while (cleaned_count);
|
|
|
|
|
|
i += rx_ring->count;
|
|
|
|
|
|
if (rx_ring->next_to_use != i) {
|
|
|
+ /* record the next descriptor to use */
|
|
|
rx_ring->next_to_use = i;
|
|
|
|
|
|
- /* Force memory writes to complete before letting h/w
|
|
|
+ /* update next to alloc since we have filled the ring */
|
|
|
+ rx_ring->next_to_alloc = i;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Force memory writes to complete before letting h/w
|
|
|
* know there are new descriptors to fetch. (Only
|
|
|
* applicable for weak-ordered memory model archs,
|
|
|
- * such as IA-64). */
|
|
|
+ * such as IA-64).
|
|
|
+ */
|
|
|
wmb();
|
|
|
writel(i, rx_ring->tail);
|
|
|
}
|
|
@@ -6492,7 +6862,9 @@ static int igb_resume(struct device *dev)
|
|
|
wr32(E1000_WUS, ~0);
|
|
|
|
|
|
if (netdev->flags & IFF_UP) {
|
|
|
+ rtnl_lock();
|
|
|
err = __igb_open(netdev, true);
|
|
|
+ rtnl_unlock();
|
|
|
if (err)
|
|
|
return err;
|
|
|
}
|