static unsigned long __ref kernel_map_range()

in mm/init_64.c [1758:1855]


static unsigned long __ref kernel_map_range(unsigned long pstart,
					    unsigned long pend, pgprot_t prot,
					    bool use_huge)
{
	unsigned long vstart = PAGE_OFFSET + pstart;
	unsigned long vend = PAGE_OFFSET + pend;
	unsigned long alloc_bytes = 0UL;

	if ((vstart & ~PAGE_MASK) || (vend & ~PAGE_MASK)) {
		prom_printf("kernel_map: Unaligned physmem[%lx:%lx]\n",
			    vstart, vend);
		prom_halt();
	}

	while (vstart < vend) {
		unsigned long this_end, paddr = __pa(vstart);
		pgd_t *pgd = pgd_offset_k(vstart);
		p4d_t *p4d;
		pud_t *pud;
		pmd_t *pmd;
		pte_t *pte;

		if (pgd_none(*pgd)) {
			pud_t *new;

			new = memblock_alloc_from(PAGE_SIZE, PAGE_SIZE,
						  PAGE_SIZE);
			if (!new)
				goto err_alloc;
			alloc_bytes += PAGE_SIZE;
			pgd_populate(&init_mm, pgd, new);
		}

		p4d = p4d_offset(pgd, vstart);
		if (p4d_none(*p4d)) {
			pud_t *new;

			new = memblock_alloc_from(PAGE_SIZE, PAGE_SIZE,
						  PAGE_SIZE);
			if (!new)
				goto err_alloc;
			alloc_bytes += PAGE_SIZE;
			p4d_populate(&init_mm, p4d, new);
		}

		pud = pud_offset(p4d, vstart);
		if (pud_none(*pud)) {
			pmd_t *new;

			if (kernel_can_map_hugepud(vstart, vend, use_huge)) {
				vstart = kernel_map_hugepud(vstart, vend, pud);
				continue;
			}
			new = memblock_alloc_from(PAGE_SIZE, PAGE_SIZE,
						  PAGE_SIZE);
			if (!new)
				goto err_alloc;
			alloc_bytes += PAGE_SIZE;
			pud_populate(&init_mm, pud, new);
		}

		pmd = pmd_offset(pud, vstart);
		if (pmd_none(*pmd)) {
			pte_t *new;

			if (kernel_can_map_hugepmd(vstart, vend, use_huge)) {
				vstart = kernel_map_hugepmd(vstart, vend, pmd);
				continue;
			}
			new = memblock_alloc_from(PAGE_SIZE, PAGE_SIZE,
						  PAGE_SIZE);
			if (!new)
				goto err_alloc;
			alloc_bytes += PAGE_SIZE;
			pmd_populate_kernel(&init_mm, pmd, new);
		}

		pte = pte_offset_kernel(pmd, vstart);
		this_end = (vstart + PMD_SIZE) & PMD_MASK;
		if (this_end > vend)
			this_end = vend;

		while (vstart < this_end) {
			pte_val(*pte) = (paddr | pgprot_val(prot));

			vstart += PAGE_SIZE;
			paddr += PAGE_SIZE;
			pte++;
		}
	}

	return alloc_bytes;

err_alloc:
	panic("%s: Failed to allocate %lu bytes align=%lx from=%lx\n",
	      __func__, PAGE_SIZE, PAGE_SIZE, PAGE_SIZE);
	return -ENOMEM;
}