unsignedint ef4_tx_max_skb_descs(struct ef4_nic *efx)
{ /* This is probably too much since we don't have any TSO support; * it's a left-over from when we had Software TSO. But it's safer * to leave it as-is than try to determine a new bound.
*/ /* Header and payload descriptor for each output segment, plus * one for every input fragment boundary within a segment
*/ unsignedint max_descs = EF4_TSO_MAX_SEGS * 2 + MAX_SKB_FRAGS;
/* Possibly one more per segment for the alignment workaround, * or for option descriptors
*/ if (EF4_WORKAROUND_5391(efx))
max_descs += EF4_TSO_MAX_SEGS;
/* Possibly more for PCIe page boundaries within input fragments */ if (PAGE_SIZE > EF4_PAGE_SIZE)
max_descs += max_t(unsignedint, MAX_SKB_FRAGS,
DIV_ROUND_UP(GSO_LEGACY_MAX_SIZE,
EF4_PAGE_SIZE));
return max_descs;
}
staticvoid ef4_tx_maybe_stop_queue(struct ef4_tx_queue *txq1)
{ /* We need to consider both queues that the net core sees as one */ struct ef4_tx_queue *txq2 = ef4_tx_queue_partner(txq1); struct ef4_nic *efx = txq1->efx; unsignedint fill_level;
/* We used the stale old_read_count above, which gives us a * pessimistic estimate of the fill level (which may even * validly be >= efx->txq_entries). Now try again using * read_count (more likely to be a cache miss). * * If we read read_count and then conditionally stop the * queue, it is possible for the completion path to race with * us and complete all outstanding descriptors in the middle, * after which there will be no more completions to wake it. * Therefore we stop the queue first, then read read_count * (with a memory barrier to ensure the ordering), then * restart the queue if the fill level turns out to be low * enough.
*/
netif_tx_stop_queue(txq1->core_txq);
smp_mb();
txq1->old_read_count = READ_ONCE(txq1->read_count);
txq2->old_read_count = READ_ONCE(txq2->read_count);
/* The final descriptor for a fragment is responsible for * unmapping the whole fragment.
*/
buffer->flags = EF4_TX_BUF_CONT | dma_flags;
buffer->unmap_len = unmap_len;
buffer->dma_offset = buffer->dma_addr - unmap_addr;
if (frag_index >= nr_frags) { /* Store SKB details with the final buffer for * the completion.
*/
buffer->skb = skb;
buffer->flags = EF4_TX_BUF_SKB | dma_flags; return 0;
}
/* Move on to the next fragment. */
fragment = &skb_shinfo(skb)->frags[frag_index++];
len = skb_frag_size(fragment);
dma_addr = skb_frag_dma_map(dma_dev, fragment,
0, len, DMA_TO_DEVICE);
dma_flags = 0;
unmap_len = len;
unmap_addr = dma_addr;
if (unlikely(dma_mapping_error(dma_dev, dma_addr))) return -EIO;
} while (1);
}
/* Remove buffers put into a tx_queue. None of the buffers must have * an skb attached.
*/ staticvoid ef4_enqueue_unwind(struct ef4_tx_queue *tx_queue)
{ struct ef4_tx_buffer *buffer;
/* Work backwards until we hit the original insert pointer value */ while (tx_queue->insert_count != tx_queue->write_count) {
--tx_queue->insert_count;
buffer = __ef4_tx_queue_get_insert_buffer(tx_queue);
ef4_dequeue_buffer(tx_queue, buffer, NULL, NULL);
}
}
/* * Add a socket buffer to a TX queue * * This maps all fragments of a socket buffer for DMA and adds them to * the TX queue. The queue's insert pointer will be incremented by * the number of fragments in the socket buffer. * * If any DMA mapping fails, any mapped fragments will be unmapped, * the queue's insert pointer will be restored to its original value. * * This function is split out from ef4_hard_start_xmit to allow the * loopback test to direct packets via specific TX queues. * * Returns NETDEV_TX_OK. * You must hold netif_tx_lock() to call this function.
*/
netdev_tx_t ef4_enqueue_skb(struct ef4_tx_queue *tx_queue, struct sk_buff *skb)
{ bool data_mapped = false; unsignedint skb_len;
/* Pass off to hardware */ if (!netdev_xmit_more() || netif_xmit_stopped(tx_queue->core_txq)) { struct ef4_tx_queue *txq2 = ef4_tx_queue_partner(tx_queue);
/* There could be packets left on the partner queue if those * SKBs had skb->xmit_more set. If we do not push those they * could be left for a long time and cause a netdev watchdog.
*/ if (txq2->xmit_more_available)
ef4_nic_push_buffers(txq2);
/* Remove packets from the TX queue * * This removes packets from the TX queue, up to and including the * specified index.
*/ staticvoid ef4_dequeue_buffers(struct ef4_tx_queue *tx_queue, unsignedint index, unsignedint *pkts_compl, unsignedint *bytes_compl)
{ struct ef4_nic *efx = tx_queue->efx; unsignedint stop_index, read_ptr;
/* Initiate a packet transmission. We use one channel per CPU * (sharing when we have more CPUs than channels). On Falcon, the TX * completion events will be directed back to the CPU that transmitted * the packet, which should be cache-efficient. * * Context: non-blocking. * Note that returning anything other than NETDEV_TX_OK will cause the * OS to free the skb.
*/
netdev_tx_t ef4_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
{ struct ef4_nic *efx = netdev_priv(net_dev); struct ef4_tx_queue *tx_queue; unsigned index, type;
/* Do not destroy high-priority queues when they become * unused. We would have to flush them first, and it is * fairly difficult to flush a subset of TX queues. Leave * it to ef4_fini_channels().
*/
/* See if we need to restart the netif queue. This memory * barrier ensures that we write read_count (inside * ef4_dequeue_buffers()) before reading the queue status.
*/
smp_mb(); if (unlikely(netif_tx_queue_stopped(tx_queue->core_txq)) &&
likely(efx->port_enabled) &&
likely(netif_device_present(efx->net_dev))) {
txq2 = ef4_tx_queue_partner(tx_queue);
fill_level = max(tx_queue->insert_count - tx_queue->read_count,
txq2->insert_count - txq2->read_count); if (fill_level <= efx->txq_wake_thresh)
netif_tx_wake_queue(tx_queue->core_txq);
}
/* Check whether the hardware queue is now empty */ if ((int)(tx_queue->read_count - tx_queue->old_write_count) >= 0) {
tx_queue->old_write_count = READ_ONCE(tx_queue->write_count); if (tx_queue->read_count == tx_queue->old_write_count) {
smp_mb();
tx_queue->empty_read_count =
tx_queue->read_count | EF4_EMPTY_COUNT_VALID;
}
}
}
netif_dbg(tx_queue->efx, drv, tx_queue->efx->net_dev, "shutting down TX queue %d\n", tx_queue->queue);
if (!tx_queue->buffer) return;
/* Free any buffers left in the ring */ while (tx_queue->read_count != tx_queue->write_count) { unsignedint pkts_compl = 0, bytes_compl = 0;
buffer = &tx_queue->buffer[tx_queue->read_count & tx_queue->ptr_mask];
ef4_dequeue_buffer(tx_queue, buffer, &pkts_compl, &bytes_compl);
if (tx_queue->cb_page) { for (i = 0; i < ef4_tx_cb_page_count(tx_queue); i++)
ef4_nic_free_buffer(tx_queue->efx,
&tx_queue->cb_page[i]);
kfree(tx_queue->cb_page);
tx_queue->cb_page = NULL;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.