arch/m68k/mm/kmap.c

Source file repositories/reference/linux-study-clean/arch/m68k/mm/kmap.c

File Facts

System
Linux kernel
Corpus path
arch/m68k/mm/kmap.c
Extension
.c
Size
8713 bytes
Lines
401
Domain
Architecture Layer
Bucket
arch/m68k
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

if (pud_bad(*pud_dir)) {
			printk("iounmap: bad pud(%08lx)\n", pud_val(*pud_dir));
			pud_clear(pud_dir);
			return;
		}
		pmd_dir = pmd_offset(pud_dir, virtaddr);

#if CONFIG_PGTABLE_LEVELS == 3
		if (CPU_IS_020_OR_030) {
			int pmd_type = pmd_val(*pmd_dir) & _DESCTYPE_MASK;

			if (pmd_type == _PAGE_PRESENT) {
				pmd_clear(pmd_dir);
				virtaddr += PMD_SIZE;
				size -= PMD_SIZE;

			} else if (pmd_type == 0)
				continue;
		}
#endif

		if (pmd_bad(*pmd_dir)) {
			printk("iounmap: bad pmd (%08lx)\n", pmd_val(*pmd_dir));
			pmd_clear(pmd_dir);
			return;
		}
		pte_dir = pte_offset_kernel(pmd_dir, virtaddr);

		pte_val(*pte_dir) = 0;
		virtaddr += PAGE_SIZE;
		size -= PAGE_SIZE;
	}

	flush_tlb_all();
}

static struct vm_struct *get_io_area(unsigned long size)
{
	unsigned long addr;
	struct vm_struct **p, *tmp, *area;

	area = kmalloc_obj(*area);
	if (!area)
		return NULL;
	addr = KMAP_START;
	for (p = &iolist; (tmp = *p) ; p = &tmp->next) {
		if (size + addr < (unsigned long)tmp->addr)
			break;
		if (addr > KMAP_END-size) {
			kfree(area);
			return NULL;
		}
		addr = tmp->size + (unsigned long)tmp->addr;
	}
	area->addr = (void *)addr;
	area->size = size + IO_SIZE;
	area->next = *p;
	*p = area;
	return area;
}

static inline void free_io_area(void *addr)
{
	struct vm_struct **p, *tmp;

	if (!addr)
		return;
	addr = (void *)((unsigned long)addr & -IO_SIZE);
	for (p = &iolist ; (tmp = *p) ; p = &tmp->next) {
		if (tmp->addr == addr) {
			*p = tmp->next;
			/* remove gap added in get_io_area() */
			__free_io_area(tmp->addr, tmp->size - IO_SIZE);
			kfree(tmp);
			return;
		}
	}
}

#endif

/*
 * Map some physical address range into the kernel address space.
 */
/* Rewritten by Andreas Schwab to remove all races. */

void __iomem *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
{
	struct vm_struct *area;
	unsigned long virtaddr, retaddr;

Annotation

Implementation Notes