drivers/net/ethernet/sfc/ef100_tx.c

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

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/sfc/ef100_tx.c
Extension
.c
Size
16220 bytes
Lines
521
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

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_doorbell to avoid a race with the
	 * completion path, so ensure these operations are not
	 * re-ordered.  This also flushes the update of write_count
	 * back into the cache.
	 */
	smp_mb();
}

void ef100_tx_write(struct efx_tx_queue *tx_queue)
{
	ef100_tx_make_descriptors(tx_queue, NULL, 0, NULL);
	ef100_tx_push_buffers(tx_queue);
}

int ef100_ev_tx(struct efx_channel *channel, const efx_qword_t *p_event)
{
	unsigned int tx_done =
		EFX_QWORD_FIELD(*p_event, ESF_GZ_EV_TXCMPL_NUM_DESC);
	unsigned int qlabel =
		EFX_QWORD_FIELD(*p_event, ESF_GZ_EV_TXCMPL_Q_LABEL);
	struct efx_tx_queue *tx_queue =
		efx_channel_get_tx_queue(channel, qlabel);
	unsigned int tx_index = (tx_queue->read_count + tx_done - 1) &
				tx_queue->ptr_mask;

	return efx_xmit_done(tx_queue, tx_index);
}

/* Add a socket buffer to a TX queue
 *
 * You must hold netif_tx_lock() to call this function.
 *
 * Returns 0 on success, error code otherwise. In case of an error this
 * function will free the SKB.
 */
netdev_tx_t ef100_enqueue_skb(struct efx_tx_queue *tx_queue,
			      struct sk_buff *skb)
{
	return __ef100_enqueue_skb(tx_queue, skb, NULL);
}

int __ef100_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb,
			struct efx_rep *efv)
{
	unsigned int old_insert_count = tx_queue->insert_count;
	struct efx_nic *efx = tx_queue->efx;
	bool xmit_more = netdev_xmit_more();
	unsigned int fill_level;
	unsigned int segments;
	int rc;

	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;

Annotation

Implementation Notes