drivers/net/ethernet/sfc/tx_common.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/sfc/tx_common.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/sfc/tx_common.c
Extension
.c
Size
13785 bytes
Lines
488
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (unlikely(buffer->flags & EFX_TX_BUF_EFV)) {
			EFX_WARN_ON_PARANOID(!efv_pkts_compl);
			(*efv_pkts_compl)++;
		} else {
			EFX_WARN_ON_PARANOID(!pkts_compl || !bytes_compl);
			(*pkts_compl)++;
			(*bytes_compl) += skb->len;
		}

		if (tx_queue->timestamping &&
		    (tx_queue->completed_timestamp_major ||
		     tx_queue->completed_timestamp_minor)) {
			struct skb_shared_hwtstamps hwtstamp;

			hwtstamp.hwtstamp =
				efx_ptp_nic_to_kernel_time(tx_queue);
			skb_tstamp_tx(skb, &hwtstamp);

			tx_queue->completed_timestamp_major = 0;
			tx_queue->completed_timestamp_minor = 0;
		}
		dev_consume_skb_any((struct sk_buff *)buffer->skb);
		netif_vdbg(tx_queue->efx, tx_done, tx_queue->efx->net_dev,
			   "TX queue %d transmission id %x complete\n",
			   tx_queue->queue, tx_queue->read_count);
	} else if (buffer->flags & EFX_TX_BUF_XDP) {
		xdp_return_frame_rx_napi(buffer->xdpf);
		if (xdp_pkts)
			(*xdp_pkts)++;
		if (xdp_bytes)
			(*xdp_bytes) += buffer->xdpf->len;
	}

	buffer->len = 0;
	buffer->flags = 0;
}

/* Remove packets from the TX queue
 *
 * This removes packets from the TX queue, up to and including the
 * specified index.
 */
static void efx_dequeue_buffers(struct efx_tx_queue *tx_queue,
				unsigned int index,
				unsigned int *pkts_compl,
				unsigned int *bytes_compl,
				unsigned int *efv_pkts_compl,
				unsigned int *xdp_pkts,
				unsigned int *xdp_bytes)
{
	struct efx_nic *efx = tx_queue->efx;
	unsigned int stop_index, read_ptr;

	stop_index = (index + 1) & tx_queue->ptr_mask;
	read_ptr = tx_queue->read_count & tx_queue->ptr_mask;

	while (read_ptr != stop_index) {
		struct efx_tx_buffer *buffer = &tx_queue->buffer[read_ptr];

		if (!efx_tx_buffer_in_use(buffer)) {
			netif_err(efx, tx_err, efx->net_dev,
				  "TX queue %d spurious TX completion id %d\n",
				  tx_queue->queue, read_ptr);
			efx_schedule_reset(efx, RESET_TYPE_TX_SKIP);
			return;
		}

		efx_dequeue_buffer(tx_queue, buffer, pkts_compl, bytes_compl,
				   efv_pkts_compl, xdp_pkts, xdp_bytes);

		++tx_queue->read_count;
		read_ptr = tx_queue->read_count & tx_queue->ptr_mask;
	}
}

void efx_xmit_done_check_empty(struct efx_tx_queue *tx_queue)
{
	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) {
			/* Ensure that read_count is flushed. */
			smp_mb();
			tx_queue->empty_read_count =
				tx_queue->read_count | EFX_EMPTY_COUNT_VALID;
		}
	}
}

int efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
{

Annotation

Implementation Notes