/*
 * arch/s390x/kl_page.c
 *
 * This file handles the architecture-dependent parts of KLIB for
 * s390x systems.
 *
 * S390x version
 *   Copyright (C) 2001 IBM Deutschland Entwicklung GmbH,
 *                      IBM Corporation
 *
 * Derived from arch/asm-i386/kl_page.c
 *   Copyright 1999 Silicon Graphics, Inc. All rights reserved.
 *   Copyright 2000 Junichi Nomura, NEC Solutions <j-nomura@ce.jp.nec.com>
 */
#include <klib.h>

/*
 * page table traversal functions
 */

kaddr_t pgd_offset(kaddr_t pgd_base, kaddr_t vaddr)
{
	kaddr_t pgd_off, pgd_entry, pmd_base;

	pgd_off = ((vaddr >> KL_PGDIR_SHIFT)&(KL_PTRS_PER_PGD-1)) * KL_NBPW;
	kl_vtop((pgd_base + pgd_off), &pgd_entry);
	kl_readmem(pgd_entry, KL_NBPW, &pmd_base);

	return pmd_base;
}

kaddr_t pmd_offset(kaddr_t pmd_base, kaddr_t vaddr)
{
	kaddr_t pmd_off, pmd_entry, pte_base;

	pmd_off = ((vaddr >> KL_PMD_SHIFT) & (KL_PTRS_PER_PMD-1)) * KL_NBPW;
	kl_vtop((pmd_base + pmd_off), &pmd_entry);
	kl_readmem(pmd_entry, KL_NBPW, &pte_base);

	return pte_base;
}

kaddr_t pte_offset(kaddr_t pte_base, kaddr_t vaddr)
{
	kaddr_t pte_off, pte, pte_val;

	pte_off = ((vaddr >> KL_PAGE_SHIFT) & (KL_PTRS_PER_PTE-1)) * KL_NBPW;
	kl_vtop((pte_base + pte_off), &pte);
	kl_readmem(pte, KL_NBPW, &pte_val);

	return pte_val;
}

kaddr_t mmap_virtop(kaddr_t vaddr, void *mmp)
{
	kaddr_t pgd_base, pmd_base;
	kaddr_t pte_base, pte_val;
	paddr_t paddr;

	/* pgd_offset, pmd_offset, pte_offset is architecture dependent */
	pgd_base = kl_kaddr(mmp, "mm_struct", "pgd");
	pmd_base = pgd_offset(pgd_base,vaddr);
	if (KL_ERROR) {
		return(0);
	}

	/* add KL_PAGE_OFFSET to make pmd_base as virtual address */
	pmd_base = pmd_base & KL_PMD_BASE_MASK;
	pte_base = pmd_offset(pmd_base,vaddr);
	if (KL_ERROR) {
		return(0);
	}

	/* add KL_PAGE_OFFSET to make pte_base as virtual address */
	pte_base = pte_base & KL_PT_BASE_MASK;
	pte_val = pte_offset(pte_base,vaddr);
	if (KL_ERROR) {
		return(0);
	}

	paddr = (pte_val & KL_PAGE_BASE_MASK) | 
		(vaddr & (~(KL_PAGE_MASK)));
	return(paddr);
}
