drivers/net/ethernet/meta/fbnic/fbnic_txrx.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
Extension
.c
Size
75406 bytes
Lines
2956
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

struct fbnic_xmit_cb {
	u32 bytecount;
	u16 gso_segs;
	u8 desc_count;
	u8 flags;
	int hw_head;
};

#define FBNIC_XMIT_CB(__skb) ((struct fbnic_xmit_cb *)((__skb)->cb))

#define FBNIC_XMIT_NOUNMAP	((void *)1)

u32 __iomem *fbnic_ring_csr_base(const struct fbnic_ring *ring)
{
	unsigned long csr_base = (unsigned long)ring->doorbell;

	csr_base &= ~(FBNIC_QUEUE_STRIDE * sizeof(u32) - 1);

	return (u32 __iomem *)csr_base;
}

static u32 fbnic_ring_rd32(struct fbnic_ring *ring, unsigned int csr)
{
	u32 __iomem *csr_base = fbnic_ring_csr_base(ring);

	return readl(csr_base + csr);
}

static void fbnic_ring_wr32(struct fbnic_ring *ring, unsigned int csr, u32 val)
{
	u32 __iomem *csr_base = fbnic_ring_csr_base(ring);

	writel(val, csr_base + csr);
}

/**
 * fbnic_ts40_to_ns() - convert descriptor timestamp to PHC time
 * @fbn: netdev priv of the FB NIC
 * @ts40: timestamp read from a descriptor
 *
 * Return: u64 value of PHC time in nanoseconds
 *
 * Convert truncated 40 bit device timestamp as read from a descriptor
 * to the full PHC time in nanoseconds.
 */
static __maybe_unused u64 fbnic_ts40_to_ns(struct fbnic_net *fbn, u64 ts40)
{
	unsigned int s;
	u64 time_ns;
	s64 offset;
	u8 ts_top;
	u32 high;

	do {
		s = u64_stats_fetch_begin(&fbn->time_seq);
		offset = READ_ONCE(fbn->time_offset);
	} while (u64_stats_fetch_retry(&fbn->time_seq, s));

	high = READ_ONCE(fbn->time_high);

	/* Bits 63..40 from periodic clock reads, 39..0 from ts40 */
	time_ns = (u64)(high >> 8) << 40 | ts40;

	/* Compare bits 32-39 between periodic reads and ts40,
	 * see if HW clock may have wrapped since last read. We are sure
	 * that periodic reads are always at least ~1 minute behind, so
	 * this logic works perfectly fine.
	 */
	ts_top = ts40 >> 32;
	if (ts_top < (u8)high && (u8)high - ts_top > U8_MAX / 2)
		time_ns += 1ULL << 40;

	return time_ns + offset;
}

static unsigned int fbnic_desc_unused(struct fbnic_ring *ring)
{
	return (ring->head - ring->tail - 1) & ring->size_mask;
}

static unsigned int fbnic_desc_used(struct fbnic_ring *ring)
{
	return (ring->tail - ring->head) & ring->size_mask;
}

static struct netdev_queue *txring_txq(const struct net_device *dev,
				       const struct fbnic_ring *ring)
{
	return netdev_get_tx_queue(dev, ring->q_idx);
}

Annotation

Implementation Notes