drivers/firmware/tegra/ivc.c

Source file repositories/reference/linux-study-clean/drivers/firmware/tegra/ivc.c

File Facts

System
Linux kernel
Corpus path
drivers/firmware/tegra/ivc.c
Extension
.c
Size
19691 bytes
Lines
722
Domain
Driver Families
Bucket
drivers/firmware
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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 tegra_ivc_header {
	union {
		struct {
			/* fields owned by the transmitting end */
			u32 count;
			u32 state;
		};

		u8 pad[TEGRA_IVC_ALIGN];
	} tx;

	union {
		/* fields owned by the receiving end */
		u32 count;
		u8 pad[TEGRA_IVC_ALIGN];
	} rx;
};

#define tegra_ivc_header_read_field(hdr, field) \
	iosys_map_rd_field(hdr, 0, struct tegra_ivc_header, field)

#define tegra_ivc_header_write_field(hdr, field, value) \
	iosys_map_wr_field(hdr, 0, struct tegra_ivc_header, field, value)

static inline void tegra_ivc_invalidate(struct tegra_ivc *ivc, dma_addr_t phys)
{
	if (!ivc->peer)
		return;

	dma_sync_single_for_cpu(ivc->peer, phys, TEGRA_IVC_ALIGN,
				DMA_FROM_DEVICE);
}

static inline void tegra_ivc_flush(struct tegra_ivc *ivc, dma_addr_t phys)
{
	if (!ivc->peer)
		return;

	dma_sync_single_for_device(ivc->peer, phys, TEGRA_IVC_ALIGN,
				   DMA_TO_DEVICE);
}

static inline bool tegra_ivc_empty(struct tegra_ivc *ivc, struct iosys_map *map)
{
	/*
	 * This function performs multiple checks on the same values with
	 * security implications, so create snapshots with READ_ONCE() to
	 * ensure that these checks use the same values.
	 */
	u32 tx = tegra_ivc_header_read_field(map, tx.count);
	u32 rx = tegra_ivc_header_read_field(map, rx.count);

	/*
	 * Perform an over-full check to prevent denial of service attacks
	 * where a server could be easily fooled into believing that there's
	 * an extremely large number of frames ready, since receivers are not
	 * expected to check for full or over-full conditions.
	 *
	 * Although the channel isn't empty, this is an invalid case caused by
	 * a potentially malicious peer, so returning empty is safer, because
	 * it gives the impression that the channel has gone silent.
	 */
	if (tx - rx > ivc->num_frames)
		return true;

	return tx == rx;
}

static inline bool tegra_ivc_full(struct tegra_ivc *ivc, struct iosys_map *map)
{
	u32 tx = tegra_ivc_header_read_field(map, tx.count);
	u32 rx = tegra_ivc_header_read_field(map, rx.count);

	/*
	 * Invalid cases where the counters indicate that the queue is over
	 * capacity also appear full.
	 */
	return tx - rx >= ivc->num_frames;
}

static inline u32 tegra_ivc_available(struct tegra_ivc *ivc, struct iosys_map *map)
{
	u32 tx = tegra_ivc_header_read_field(map, tx.count);
	u32 rx = tegra_ivc_header_read_field(map, rx.count);

	/*
	 * This function isn't expected to be used in scenarios where an
	 * over-full situation can lead to denial of service attacks. See the
	 * comment in tegra_ivc_empty() for an explanation about special
	 * over-full considerations.

Annotation

Implementation Notes