arch/sparc/mm/io-unit.c
Source file repositories/reference/linux-study-clean/arch/sparc/mm/io-unit.c
File Facts
- System
- Linux kernel
- Corpus path
arch/sparc/mm/io-unit.c- Extension
.c- Size
- 7620 bytes
- Lines
- 289
- 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.
- CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.
- Exports symbols or registers init work; inspect boot/module ordering and who consumes the exported contract.
- Uses kernel synchronization; read lock ordering, sleepability, and interrupt context assumptions before translating.
- Touches IRQ or DMA behavior; this matters for the representative real-device path.
- Allocates kernel memory; connect allocation flags and lifetime to context constraints.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/kernel.hlinux/init.hlinux/slab.hlinux/spinlock.hlinux/mm.hlinux/bitops.hlinux/dma-map-ops.hlinux/of.hlinux/of_platform.hlinux/platform_device.hasm/io.hasm/io-unit.hasm/mxcc.hasm/cacheflush.hasm/tlbflush.hasm/dma.hasm/oplib.hmm_32.h
Detected Declarations
function iounit_iommu_initfunction iounit_initfunction for_each_node_by_namefunction iounit_get_areafunction iounit_map_physfunction iounit_map_sgfunction iounit_unmap_physfunction iounit_unmap_sgfunction iounit_freemodule init iounit_init
Annotated Snippet
subsys_initcall(iounit_init);
/* One has to hold iounit->lock to call this */
static dma_addr_t iounit_get_area(struct iounit_struct *iounit,
phys_addr_t phys, int size)
{
int i, j, k, npages;
unsigned long rotor, scan, limit;
iopte_t iopte;
npages = (offset_in_page(phys) + size + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
/* A tiny bit of magic ingredience :) */
switch (npages) {
case 1: i = 0x0231; break;
case 2: i = 0x0132; break;
default: i = 0x0213; break;
}
IOD(("%s(%pa,%d[%d])=", __func__, &phys, size, npages));
next: j = (i & 15);
rotor = iounit->rotor[j - 1];
limit = iounit->limit[j];
scan = rotor;
nexti: scan = find_next_zero_bit(iounit->bmap, limit, scan);
if (scan + npages > limit) {
if (limit != rotor) {
limit = rotor;
scan = iounit->limit[j - 1];
goto nexti;
}
i >>= 4;
if (!(i & 15))
panic("iounit_get_area: Couldn't find free iopte slots for (%pa,%d)\n",
&phys, size);
goto next;
}
for (k = 1, scan++; k < npages; k++)
if (test_bit(scan++, iounit->bmap))
goto nexti;
iounit->rotor[j - 1] = (scan < limit) ? scan : iounit->limit[j - 1];
scan -= npages;
iopte = MKIOPTE(phys & PAGE_MASK);
phys = IOUNIT_DMA_BASE + (scan << PAGE_SHIFT) + offset_in_page(phys);
for (k = 0; k < npages; k++, iopte = __iopte(iopte_val(iopte) + 0x100), scan++) {
set_bit(scan, iounit->bmap);
sbus_writel(iopte_val(iopte), &iounit->page_table[scan]);
}
IOD(("%pa\n", &phys));
return phys;
}
static dma_addr_t iounit_map_phys(struct device *dev, phys_addr_t phys,
size_t len, enum dma_data_direction dir, unsigned long attrs)
{
struct iounit_struct *iounit = dev->archdata.iommu;
unsigned long flags;
dma_addr_t ret;
/* XXX So what is maxphys for us and how do drivers know it? */
if (!len || len > 256 * 1024)
return DMA_MAPPING_ERROR;
spin_lock_irqsave(&iounit->lock, flags);
ret = iounit_get_area(iounit, phys, len);
spin_unlock_irqrestore(&iounit->lock, flags);
return ret;
}
static int iounit_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
enum dma_data_direction dir, unsigned long attrs)
{
struct iounit_struct *iounit = dev->archdata.iommu;
struct scatterlist *sg;
unsigned long flags;
int i;
/* FIXME: Cache some resolved pages - often several sg entries are to the same page */
spin_lock_irqsave(&iounit->lock, flags);
for_each_sg(sgl, sg, nents, i) {
sg->dma_address =
iounit_get_area(iounit, sg_phys(sg), sg->length);
sg->dma_length = sg->length;
}
spin_unlock_irqrestore(&iounit->lock, flags);
return nents;
}
static void iounit_unmap_phys(struct device *dev, dma_addr_t vaddr, size_t len,
Annotation
- Immediate include surface: `linux/kernel.h`, `linux/init.h`, `linux/slab.h`, `linux/spinlock.h`, `linux/mm.h`, `linux/bitops.h`, `linux/dma-map-ops.h`, `linux/of.h`.
- Detected declarations: `function iounit_iommu_init`, `function iounit_init`, `function for_each_node_by_name`, `function iounit_get_area`, `function iounit_map_phys`, `function iounit_map_sg`, `function iounit_unmap_phys`, `function iounit_unmap_sg`, `function iounit_free`, `module init iounit_init`.
- Atlas domain: Architecture Layer / arch/sparc.
- Implementation status: integration implementation candidate.
- Synchronization appears in or near this file; preserve lock ordering, sleepability, and interrupt-context constraints.
- IRQ or DMA behavior appears here, which is relevant to the selected PCIe/NVMe device path.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.