int ef100_tx_probe(struct efx_tx_queue *tx_queue)
{ /* Allocate an extra descriptor for the QMDA status completion entry */ return efx_nic_alloc_buffer(tx_queue->efx, &tx_queue->txd,
(tx_queue->ptr_mask + 2) * sizeof(efx_oword_t),
GFP_KERNEL);
}
void ef100_tx_init(struct efx_tx_queue *tx_queue)
{ /* must be the inverse of lookup in efx_get_tx_channel */
tx_queue->core_txq =
netdev_get_tx_queue(tx_queue->efx->net_dev,
tx_queue->channel->channel -
tx_queue->efx->tx_channel_offset);
/* This value is purely documentational; as EF100 never passes through *theswitchstatementintx.c:__efx_enqueue_skb(),thatswitchdoes *nothandlecase3.EF100'sTSOv3descriptorsaregeneratedby *ef100_make_tso_desc(). *Meanwhile,allefx_mcdi_tx_init()caresaboutisthatit'snot2.
*/
tx_queue->tso_version = 3; if (efx_mcdi_tx_init(tx_queue))
netdev_WARN(tx_queue->efx->net_dev, "failed to initialise TXQ %d\n", tx_queue->queue);
}
if (!skb || skb->ip_summed != CHECKSUM_PARTIAL) return;
/* skb->csum_start has the offset from head, but we need the offset *fromdata.
*/
csum_start = skb_checksum_start_offset(skb);
EFX_POPULATE_OWORD_3(csum,
ESF_GZ_TX_SEND_CSO_PARTIAL_EN, 1,
ESF_GZ_TX_SEND_CSO_PARTIAL_START_W,
csum_start >> 1,
ESF_GZ_TX_SEND_CSO_PARTIAL_CSUM_W,
skb->csum_offset >> 1);
EFX_OR_OWORD(*txd, *txd, csum);
}
/* Create TX descriptor ring entry */
tx_queue->packet_write_count = new_write_count;
switch (next_desc_type) { case ESE_GZ_TX_DESC_TYPE_SEND:
ef100_make_send_desc(tx_queue->efx, skb,
buffer, txd, nr_descs); break; case ESE_GZ_TX_DESC_TYPE_TSO: /* TX TSO descriptor */
WARN_ON_ONCE(!(buffer->flags & EFX_TX_BUF_TSO_V3));
ef100_make_tso_desc(tx_queue->efx, skb,
buffer, txd, nr_descs); break; default: /* TX segment descriptor */
EFX_POPULATE_OWORD_3(*txd,
ESF_GZ_TX_DESC_TYPE, ESE_GZ_TX_DESC_TYPE_SEG,
ESF_GZ_TX_SEG_LEN, buffer->len,
ESF_GZ_TX_SEG_ADDR, buffer->dma_addr);
} /* if it's a raw write (such as XDP) then always SEND */
next_desc_type = skb ? ESE_GZ_TX_DESC_TYPE_SEG :
ESE_GZ_TX_DESC_TYPE_SEND; /* mark as an EFV buffer if applicable */ if (unlikely(efv))
buffer->flags |= EFX_TX_BUF_EFV;
} while (new_write_count != tx_queue->insert_count);
wmb(); /* Ensure descriptors are written before they are fetched */
tx_queue->write_count = new_write_count;
/* The write_count above must be updated before reading *channel->holdoff_doorbelltoavoidaracewiththe *completionpath,soensuretheseoperationsarenot *re-ordered.Thisalsoflushestheupdateofwrite_count *backintothecache.
*/
smp_mb();
}
if (!tx_queue->buffer || !tx_queue->ptr_mask) {
netif_stop_queue(efx->net_dev);
dev_kfree_skb_any(skb); return -ENODEV;
}
segments = skb_is_gso(skb) ? skb_shinfo(skb)->gso_segs : 0; if (segments == 1)
segments = 0; /* Don't use TSO/GSO for a single segment. */ if (segments && !ef100_tx_can_tso(tx_queue, skb)) {
rc = efx_tx_tso_fallback(tx_queue, skb);
tx_queue->tso_fallbacks++; if (rc) goto err; else return0;
}
if (unlikely(efv)) { struct efx_tx_buffer *buffer = __efx_tx_queue_get_insert_buffer(tx_queue);
/* Drop representor packets if the queue is stopped. *Wecurrentlydon'tassertbackofftorepresentorssothisis *tomakesurerepresentortrafficcan'tstarvethemain *netdevice. *And,ofcourse,iftherearenoTXdescriptorsleft.
*/ if (netif_tx_queue_stopped(tx_queue->core_txq) ||
unlikely(efx_tx_buffer_in_use(buffer))) {
atomic64_inc(&efv->stats.tx_errors);
rc = -ENOSPC; goto err;
}
/* Also drop representor traffic if it could cause us to *stopthequeue.Ifweassertbackoffandwehaven't *receivedtrafficonthemainnetdevicerecentlythenthe *TXwatchdogcangoofferroneously.
*/
fill_level = efx_channel_tx_old_fill_level(tx_queue->channel);
fill_level += efx_tx_max_skb_descs(efx); if (fill_level > efx->txq_stop_thresh) { struct efx_tx_queue *txq2;
/* Refresh cached fill level and re-check */
efx_for_each_channel_tx_queue(txq2, tx_queue->channel)
txq2->old_read_count = READ_ONCE(txq2->read_count);
/* Because of checks above, representor traffic should *notbeabletostopthequeue.
*/
WARN_ON(efv);
netif_tx_stop_queue(tx_queue->core_txq); /* Re-read after a memory barrier in case we've raced with *thecompletionpath.Otherwisethere'sadangerwe'llnever *restartthequeueifallcompletionshavejusthappened.
*/
smp_mb();
efx_for_each_channel_tx_queue(txq2, tx_queue->channel)
txq2->old_read_count = READ_ONCE(txq2->read_count);
fill_level = efx_channel_tx_old_fill_level(tx_queue->channel); if (fill_level < efx->txq_stop_thresh)
netif_tx_start_queue(tx_queue->core_txq);
}
tx_queue->xmit_pending = true;
/* If xmit_more then we don't need to push the doorbell, unless there *are256descriptorsalreadyqueuedinwhichcasewehavetopushto *ensureweneverpushmorethan256atonce. * *Alwayspushforrepresentortraffic,anddon'taccountittoparent *PFnetdevice'sBQL.
*/ if (unlikely(efv) ||
__netdev_tx_sent_queue(tx_queue->core_txq, skb->len, xmit_more) ||
tx_queue->write_count - tx_queue->notify_count > 255)
ef100_tx_push_buffers(tx_queue);
err:
efx_enqueue_unwind(tx_queue, old_insert_count); if (!IS_ERR_OR_NULL(skb))
dev_kfree_skb_any(skb);
/* If we're not expecting another transmit and we had something to push *onthisqueuethenweneedtopushheretogetthepreviouspackets *out.Weonlyenterthisbranchfrombeforethexmit_morehandling *above,soxmit_pendingstillreferstotheoldstate.
*/ if (tx_queue->xmit_pending && !xmit_more)
ef100_tx_push_buffers(tx_queue); return rc;
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet am 2026-09-29)
¤
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.