drivers/staging/media/ipu7/ipu7-mmu.c

Source file repositories/reference/linux-study-clean/drivers/staging/media/ipu7/ipu7-mmu.c

File Facts

System
Linux kernel
Corpus path
drivers/staging/media/ipu7/ipu7-mmu.c
Extension
.c
Size
21189 bytes
Lines
854
Domain
Driver Families
Bucket
drivers/staging
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

if (mmu_info->l1_pt[l1_idx] == mmu_info->dummy_l2_pteval) {
			dev_err(mmu_info->dev,
				"unmap not mapped iova 0x%8.8lx l1 index %u\n",
				iova, l1_idx);
			continue;
		}
		l2_pt = mmu_info->l2_pts[l1_idx];

		l2_entries = 0;
		for (l2_idx = (iova & ISP_L2PT_MASK) >> ISP_L2PT_SHIFT;
		     size > 0U && l2_idx < ISP_L2PT_PTES; l2_idx++) {
			phys_addr_t pteval = TBL_PHYS_ADDR(l2_pt[l2_idx]);

			dev_dbg(mmu_info->dev,
				"unmap l2 index %u with pteval 0x%p\n",
				l2_idx, &pteval);
			l2_pt[l2_idx] = mmu_info->dummy_page_pteval;

			iova += ISP_PAGE_SIZE;
			size -= ISP_PAGE_SIZE;

			l2_entries++;
		}

		WARN_ON_ONCE(!l2_entries);
		clflush_cache_range(&l2_pt[l2_idx - l2_entries],
				    sizeof(l2_pt[0]) * l2_entries);
	}

	WARN_ON_ONCE(size);
	spin_unlock_irqrestore(&mmu_info->lock, flags);
}

static int l2_map(struct ipu7_mmu_info *mmu_info, unsigned long iova,
		  phys_addr_t paddr, size_t size)
{
	struct device *dev = mmu_info->dev;
	unsigned int l2_entries;
	u32 *l2_pt, *l2_virt;
	unsigned int l2_idx;
	unsigned long flags;
	size_t mapped = 0;
	dma_addr_t dma;
	u32 l1_entry;
	u32 l1_idx;
	int err = 0;

	spin_lock_irqsave(&mmu_info->lock, flags);

	paddr = ALIGN(paddr, ISP_PAGE_SIZE);
	for (l1_idx = iova >> ISP_L1PT_SHIFT;
	     size && l1_idx < ISP_L1PT_PTES; l1_idx++) {
		dev_dbg(dev,
			"mapping l2 page table for l1 index %u (iova %8.8x)\n",
			l1_idx, (u32)iova);

		l1_entry = mmu_info->l1_pt[l1_idx];
		if (l1_entry == mmu_info->dummy_l2_pteval) {
			l2_virt = mmu_info->l2_pts[l1_idx];
			if (likely(!l2_virt)) {
				l2_virt = alloc_l2_pt(mmu_info);
				if (!l2_virt) {
					err = -ENOMEM;
					goto error;
				}
			}

			dma = map_single(mmu_info, l2_virt);
			if (!dma) {
				dev_err(dev, "Failed to map l2pt page\n");
				free_page((unsigned long)l2_virt);
				err = -EINVAL;
				goto error;
			}

			l1_entry = dma >> ISP_PADDR_SHIFT;

			dev_dbg(dev, "page for l1_idx %u %p allocated\n",
				l1_idx, l2_virt);
			mmu_info->l1_pt[l1_idx] = l1_entry;
			mmu_info->l2_pts[l1_idx] = l2_virt;

			clflush_cache_range(&mmu_info->l1_pt[l1_idx],
					    sizeof(mmu_info->l1_pt[l1_idx]));
		}

		l2_pt = mmu_info->l2_pts[l1_idx];
		l2_entries = 0;

		for (l2_idx = (iova & ISP_L2PT_MASK) >> ISP_L2PT_SHIFT;

Annotation

Implementation Notes