arch/powerpc/mm/book3s64/hugetlbpage.c

Source file repositories/reference/linux-study-clean/arch/powerpc/mm/book3s64/hugetlbpage.c

File Facts

System
Linux kernel
Corpus path
arch/powerpc/mm/book3s64/hugetlbpage.c
Extension
.c
Size
5005 bytes
Lines
178
Domain
Architecture Layer
Bucket
arch/powerpc
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 (IS_ENABLED(CONFIG_PPC_4K_PAGES)) {
			if (!(old_pte & _PAGE_ACCESSED))
				return 1;
			if ((access & _PAGE_WRITE) && !(old_pte & _PAGE_DIRTY))
				return 1;
		}

		/*
		 * Try to lock the PTE, add ACCESSED and DIRTY if it was
		 * a write access
		 */
		new_pte = old_pte | H_PAGE_BUSY | _PAGE_ACCESSED;
		if (access & _PAGE_WRITE)
			new_pte |= _PAGE_DIRTY;
	} while(!pte_xchg(ptep, __pte(old_pte), __pte(new_pte)));

	/* Make sure this is a hugetlb entry */
	if (old_pte & H_PAGE_THP_HUGE)
		return 0;

	rflags = htab_convert_pte_flags(new_pte, flags);
	if (unlikely(mmu_psize == MMU_PAGE_16G))
		offset = PTRS_PER_PUD;
	else
		offset = PTRS_PER_PMD;
	rpte = __real_pte(__pte(old_pte), ptep, offset);

	if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE))
		/*
		 * No CPU has hugepages but lacks no execute, so we
		 * don't need to worry about that case
		 */
		rflags = hash_page_do_lazy_icache(rflags, __pte(old_pte), trap);

	/* Check if pte already has an hpte (case 2) */
	if (unlikely(old_pte & H_PAGE_HASHPTE)) {
		/* There MIGHT be an HPTE for this pte */
		unsigned long gslot;

		gslot = pte_get_hash_gslot(vpn, shift, ssize, rpte, 0);
		if (mmu_hash_ops.hpte_updatepp(gslot, rflags, vpn, mmu_psize,
					       mmu_psize, ssize, flags) == -1)
			old_pte &= ~_PAGE_HPTEFLAGS;
	}

	if (likely(!(old_pte & H_PAGE_HASHPTE))) {
		unsigned long hash = hpt_hash(vpn, shift, ssize);

		pa = pte_pfn(__pte(old_pte)) << PAGE_SHIFT;

		/* clear HPTE slot informations in new PTE */
		new_pte = (new_pte & ~_PAGE_HPTEFLAGS) | H_PAGE_HASHPTE;

		slot = hpte_insert_repeating(hash, vpn, pa, rflags, 0,
					     mmu_psize, ssize);

		/*
		 * Hypervisor failure. Restore old pte and return -1
		 * similar to __hash_page_*
		 */
		if (unlikely(slot == -2)) {
			*ptep = __pte(old_pte);
			hash_failure_debug(ea, access, vsid, trap, ssize,
					   mmu_psize, mmu_psize, old_pte);
			return -1;
		}

		new_pte |= pte_set_hidx(ptep, rpte, 0, slot, offset);
	}

	/*
	 * No need to use ldarx/stdcx here
	 */
	*ptep = __pte(new_pte & ~H_PAGE_BUSY);
	return 0;
}
#endif

pte_t huge_ptep_modify_prot_start(struct vm_area_struct *vma,
				  unsigned long addr, pte_t *ptep)
{
	unsigned long pte_val;
	/*
	 * Clear the _PAGE_PRESENT so that no hardware parallel update is
	 * possible. Also keep the pte_present true so that we don't take
	 * wrong fault.
	 */
	pte_val = pte_update(vma->vm_mm, addr, ptep,
			     _PAGE_PRESENT, _PAGE_INVALID, 1);

Annotation

Implementation Notes