arch/sparc/mm/iommu.c

Source file repositories/reference/linux-study-clean/arch/sparc/mm/iommu.c

File Facts

System
Linux kernel
Corpus path
arch/sparc/mm/iommu.c
Extension
.c
Size
12610 bytes
Lines
458
Domain
Architecture Layer
Bucket
arch/sparc
Inferred role
Architecture Layer: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

subsys_initcall(iommu_init);

/* Flush the iotlb entries to ram. */
/* This could be better if we didn't have to flush whole pages. */
static void iommu_flush_iotlb(iopte_t *iopte, unsigned int niopte)
{
	unsigned long start;
	unsigned long end;

	start = (unsigned long)iopte;
	end = PAGE_ALIGN(start + niopte*sizeof(iopte_t));
	start &= PAGE_MASK;
	if (viking_mxcc_present) {
		while(start < end) {
			viking_mxcc_flush_page(start);
			start += PAGE_SIZE;
		}
	} else if (viking_flush) {
		while(start < end) {
			viking_flush_page(start);
			start += PAGE_SIZE;
		}
	} else {
		while(start < end) {
			__flush_page_to_ram(start);
			start += PAGE_SIZE;
		}
	}
}

static dma_addr_t __sbus_iommu_map_phys(struct device *dev, phys_addr_t paddr,
		size_t len, bool per_page_flush, unsigned long attrs)
{
	struct iommu_struct *iommu = dev->archdata.iommu;
	unsigned long off = offset_in_page(paddr);
	unsigned long npages = (off + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
	unsigned long pfn = __phys_to_pfn(paddr);
	unsigned int busa, busa0;
	iopte_t *iopte, *iopte0;
	int ioptex, i;

	if (unlikely(attrs & DMA_ATTR_MMIO))
		return DMA_MAPPING_ERROR;

	/* XXX So what is maxphys for us and how do drivers know it? */
	if (!len || len > 256 * 1024)
		return DMA_MAPPING_ERROR;

	/*
	 * We expect unmapped highmem pages to be not in the cache.
	 * XXX Is this a good assumption?
	 * XXX What if someone else unmaps it here and races us?
	 */
	if (per_page_flush && !PhysHighMem(paddr)) {
		unsigned long vaddr, p;

		vaddr = (unsigned long)phys_to_virt(paddr);
		for (p = vaddr & PAGE_MASK; p < vaddr + len; p += PAGE_SIZE)
			flush_page_for_dma(p);
	}

	/* page color = pfn of page */
	ioptex = bit_map_string_get(&iommu->usemap, npages, pfn);
	if (ioptex < 0)
		panic("iommu out");
	busa0 = iommu->start + (ioptex << PAGE_SHIFT);
	iopte0 = &iommu->page_table[ioptex];

	busa = busa0;
	iopte = iopte0;
	for (i = 0; i < npages; i++) {
		iopte_val(*iopte) = MKIOPTE(pfn, IOPERM);
		iommu_invalidate_page(iommu->regs, busa);
		busa += PAGE_SIZE;
		iopte++;
		pfn++;
	}

	iommu_flush_iotlb(iopte0, npages);
	return busa0 + off;
}

static dma_addr_t sbus_iommu_map_phys_gflush(struct device *dev,
		phys_addr_t phys, size_t len, enum dma_data_direction dir,
		unsigned long attrs)
{
	flush_page_for_dma(0);
	return __sbus_iommu_map_phys(dev, phys, len, false, attrs);
}

Annotation

Implementation Notes