drivers/net/ethernet/sfc/siena/tx_common.c

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

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/sfc/siena/tx_common.c
Extension
.c
Size
12600 bytes
Lines
448
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 (!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_siena_schedule_reset(efx, RESET_TYPE_TX_SKIP);
			return;
		}

		efx_dequeue_buffer(tx_queue, buffer, pkts_compl, bytes_compl);

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

void efx_siena_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;
		}
	}
}

void efx_siena_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
{
	unsigned int fill_level, pkts_compl = 0, bytes_compl = 0;
	struct efx_nic *efx = tx_queue->efx;

	EFX_WARN_ON_ONCE_PARANOID(index > tx_queue->ptr_mask);

	efx_dequeue_buffers(tx_queue, index, &pkts_compl, &bytes_compl);
	tx_queue->pkts_compl += pkts_compl;
	tx_queue->bytes_compl += bytes_compl;

	if (pkts_compl > 1)
		++tx_queue->merge_events;

	/* See if we need to restart the netif queue.  This memory
	 * barrier ensures that we write read_count (inside
	 * efx_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))) {
		fill_level = efx_channel_tx_fill_level(tx_queue->channel);
		if (fill_level <= efx->txq_wake_thresh)
			netif_tx_wake_queue(tx_queue->core_txq);
	}

	efx_siena_xmit_done_check_empty(tx_queue);
}

/* Remove buffers put into a tx_queue for the current packet.
 * None of the buffers must have an skb attached.
 */
void efx_siena_enqueue_unwind(struct efx_tx_queue *tx_queue,
			      unsigned int insert_count)
{
	struct efx_tx_buffer *buffer;
	unsigned int bytes_compl = 0;
	unsigned int pkts_compl = 0;

	/* Work backwards until we hit the original insert pointer value */
	while (tx_queue->insert_count != insert_count) {
		--tx_queue->insert_count;
		buffer = __efx_tx_queue_get_insert_buffer(tx_queue);
		efx_dequeue_buffer(tx_queue, buffer, &pkts_compl, &bytes_compl);
	}
}

struct efx_tx_buffer *efx_siena_tx_map_chunk(struct efx_tx_queue *tx_queue,
					     dma_addr_t dma_addr, size_t len)
{
	const struct efx_nic_type *nic_type = tx_queue->efx->type;
	struct efx_tx_buffer *buffer;
	unsigned int dma_len;

	/* Map the fragment taking account of NIC-dependent DMA limits. */
	do {
		buffer = efx_tx_queue_get_insert_buffer(tx_queue);

		if (nic_type->tx_limit_len)
			dma_len = nic_type->tx_limit_len(tx_queue, dma_addr, len);
		else

Annotation

Implementation Notes