drivers/accel/ivpu/ivpu_mmu_context.c

Source file repositories/reference/linux-study-clean/drivers/accel/ivpu/ivpu_mmu_context.c

File Facts

System
Linux kernel
Corpus path
drivers/accel/ivpu/ivpu_mmu_context.c
Extension
.c
Size
18290 bytes
Lines
655
Domain
Driver Families
Bucket
drivers/accel
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

IS_ALIGNED(vpu_addr | dma_addr, IVPU_MMU_CONT_PAGES_SIZE)) {
			ret = ivpu_mmu_context_map_cont_64k(vdev, ctx, vpu_addr, dma_addr, prot);
			map_size = IVPU_MMU_CONT_PAGES_SIZE;
		} else {
			ret = ivpu_mmu_context_map_page(vdev, ctx, vpu_addr, dma_addr, prot);
			map_size = IVPU_MMU_PAGE_SIZE;
		}

		if (ret)
			return ret;

		vpu_addr += map_size;
		dma_addr += map_size;
		size -= map_size;
	}

	return 0;
}

static void ivpu_mmu_context_set_page_ro(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
					 u64 vpu_addr)
{
	int pgd_idx = FIELD_GET(IVPU_MMU_PGD_INDEX_MASK, vpu_addr);
	int pud_idx = FIELD_GET(IVPU_MMU_PUD_INDEX_MASK, vpu_addr);
	int pmd_idx = FIELD_GET(IVPU_MMU_PMD_INDEX_MASK, vpu_addr);
	int pte_idx = FIELD_GET(IVPU_MMU_PTE_INDEX_MASK, vpu_addr);

	ctx->pgtable.pte_ptrs[pgd_idx][pud_idx][pmd_idx][pte_idx] |= IVPU_MMU_ENTRY_FLAG_RO;
}

static void ivpu_mmu_context_split_page(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
					u64 vpu_addr)
{
	int pgd_idx = FIELD_GET(IVPU_MMU_PGD_INDEX_MASK, vpu_addr);
	int pud_idx = FIELD_GET(IVPU_MMU_PUD_INDEX_MASK, vpu_addr);
	int pmd_idx = FIELD_GET(IVPU_MMU_PMD_INDEX_MASK, vpu_addr);
	int pte_idx = FIELD_GET(IVPU_MMU_PTE_INDEX_MASK, vpu_addr);

	ctx->pgtable.pte_ptrs[pgd_idx][pud_idx][pmd_idx][pte_idx] &= ~IVPU_MMU_ENTRY_FLAG_CONT;
}

static void ivpu_mmu_context_split_64k_page(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
					    u64 vpu_addr)
{
	u64 start = ALIGN_DOWN(vpu_addr, IVPU_MMU_CONT_PAGES_SIZE);
	u64 end = ALIGN(vpu_addr, IVPU_MMU_CONT_PAGES_SIZE);
	u64 offset = 0;

	ivpu_dbg(vdev, MMU_MAP, "Split 64K page ctx: %u vpu_addr: 0x%llx\n", ctx->id, vpu_addr);

	while (start + offset < end) {
		ivpu_mmu_context_split_page(vdev, ctx, start + offset);
		offset += IVPU_MMU_PAGE_SIZE;
	}
}

int
ivpu_mmu_context_set_pages_ro(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, u64 vpu_addr,
			      size_t size)
{
	u64 end = vpu_addr + size;
	size_t size_left = size;
	int ret;

	if (size == 0)
		return 0;

	if (drm_WARN_ON(&vdev->drm, !IS_ALIGNED(vpu_addr | size, IVPU_MMU_PAGE_SIZE)))
		return -EINVAL;

	mutex_lock(&ctx->lock);

	ivpu_dbg(vdev, MMU_MAP, "Set read-only pages ctx: %u vpu_addr: 0x%llx size: %lu\n",
		 ctx->id, vpu_addr, size);

	if (!ivpu_disable_mmu_cont_pages) {
		/* Split 64K contiguous page at the beginning if needed */
		if (!IS_ALIGNED(vpu_addr, IVPU_MMU_CONT_PAGES_SIZE))
			ivpu_mmu_context_split_64k_page(vdev, ctx, vpu_addr);

		/* Split 64K contiguous page at the end if needed */
		if (!IS_ALIGNED(vpu_addr + size, IVPU_MMU_CONT_PAGES_SIZE))
			ivpu_mmu_context_split_64k_page(vdev, ctx, vpu_addr + size);
	}

	while (size_left) {
		if (vpu_addr < end)
			ivpu_mmu_context_set_page_ro(vdev, ctx, vpu_addr);

		vpu_addr += IVPU_MMU_PAGE_SIZE;

Annotation

Implementation Notes