arch/powerpc/mm/book3s64/hash_64k.c
Source file repositories/reference/linux-study-clean/arch/powerpc/mm/book3s64/hash_64k.c
File Facts
- System
- Linux kernel
- Corpus path
arch/powerpc/mm/book3s64/hash_64k.c- Extension
.c- Size
- 9380 bytes
- Lines
- 344
- Domain
- Architecture Layer
- Bucket
- arch/powerpc
- Inferred role
- Architecture Layer: implementation source
- Status
- source 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.
Dependency Surface
linux/mm.hasm/machdep.hasm/mmu.hinternal.h
Detected Declarations
function hpte_soft_invalidfunction __rpte_sub_validfunction __hash_page_4Kfunction __hash_page_64K
Annotated Snippet
if (unlikely(soft_invalid)) {
/*
* We got a valid slot from a hardware point of view.
* but we cannot use it, because we use this special
* value; as defined by hpte_soft_invalid(), to track
* invalid slots. We cannot use it. So invalidate it.
*/
gslot = slot & _PTEIDX_GROUP_IX;
mmu_hash_ops.hpte_invalidate(hpte_group + gslot, vpn,
MMU_PAGE_4K, MMU_PAGE_4K,
ssize, 0);
}
if (unlikely(slot == -1 || soft_invalid)) {
/*
* For soft invalid slot, let's ensure that we release a
* slot from the primary, with the hope that we will
* acquire that slot next time we try. This will ensure
* that we do not get the same soft-invalid slot.
*/
if (soft_invalid || (mftb() & 0x1))
hpte_group = (hash & htab_hash_mask) * HPTES_PER_GROUP;
mmu_hash_ops.hpte_remove(hpte_group);
/*
* FIXME!! Should be try the group from which we removed ?
*/
goto repeat;
}
}
/*
* 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_PAGE_4K, MMU_PAGE_4K, old_pte);
return -1;
}
new_pte |= pte_set_hidx(ptep, rpte, subpg_index, slot, PTRS_PER_PTE);
new_pte |= H_PAGE_HASHPTE;
if (stress_hpt())
hpt_do_stress(ea, hpte_group);
*ptep = __pte(new_pte & ~H_PAGE_BUSY);
return 0;
}
int __hash_page_64K(unsigned long ea, unsigned long access,
unsigned long vsid, pte_t *ptep, unsigned long trap,
unsigned long flags, int ssize)
{
real_pte_t rpte;
unsigned long hpte_group;
unsigned long rflags, pa;
unsigned long old_pte, new_pte;
unsigned long vpn, hash, slot;
unsigned long shift = mmu_psize_defs[MMU_PAGE_64K].shift;
/*
* atomically mark the linux large page PTE busy and dirty
*/
do {
pte_t pte = READ_ONCE(*ptep);
old_pte = pte_val(pte);
/* If PTE busy, retry the access */
if (unlikely(old_pte & H_PAGE_BUSY))
return 0;
/* If PTE permissions don't match, take page fault */
if (unlikely(!check_pte_access(access, old_pte)))
return 1;
/*
* Check if PTE has the cache-inhibit bit set
* If so, bail out and refault as a 4k page
*/
if (!mmu_has_feature(MMU_FTR_CI_LARGE_PAGE) &&
unlikely(pte_ci(pte)))
return 0;
/*
* 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)));
Annotation
- Immediate include surface: `linux/mm.h`, `asm/machdep.h`, `asm/mmu.h`, `internal.h`.
- Detected declarations: `function hpte_soft_invalid`, `function __rpte_sub_valid`, `function __hash_page_4K`, `function __hash_page_64K`.
- Atlas domain: Architecture Layer / arch/powerpc.
- Implementation status: source implementation candidate.
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.