2007-04-30 14:30:56 +08:00
|
|
|
#ifndef _ASM_POWERPC_PGTABLE_PPC64_H_
|
|
|
|
#define _ASM_POWERPC_PGTABLE_PPC64_H_
|
|
|
|
/*
|
|
|
|
* This file contains the functions and defines necessary to modify and use
|
|
|
|
* the ppc64 hashed page table.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef __ASSEMBLY__
|
|
|
|
#include <linux/stddef.h>
|
|
|
|
#include <asm/tlbflush.h>
|
|
|
|
#endif /* __ASSEMBLY__ */
|
|
|
|
|
|
|
|
#ifdef CONFIG_PPC_64K_PAGES
|
|
|
|
#include <asm/pgtable-64k.h>
|
|
|
|
#else
|
|
|
|
#include <asm/pgtable-4k.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define FIRST_USER_ADDRESS 0
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Size of EA range mapped by our pagetables.
|
|
|
|
*/
|
|
|
|
#define PGTABLE_EADDR_SIZE (PTE_INDEX_SIZE + PMD_INDEX_SIZE + \
|
|
|
|
PUD_INDEX_SIZE + PGD_INDEX_SIZE + PAGE_SHIFT)
|
[POWERPC] Rewrite IO allocation & mapping on powerpc64
This rewrites pretty much from scratch the handling of MMIO and PIO
space allocations on powerpc64. The main goals are:
- Get rid of imalloc and use more common code where possible
- Simplify the current mess so that PIO space is allocated and
mapped in a single place for PCI bridges
- Handle allocation constraints of PIO for all bridges including
hot plugged ones within the 2GB space reserved for IO ports,
so that devices on hotplugged busses will now work with drivers
that assume IO ports fit in an int.
- Cleanup and separate tracking of the ISA space in the reserved
low 64K of IO space. No ISA -> Nothing mapped there.
I booted a cell blade with IDE on PIO and MMIO and a dual G5 so
far, that's it :-)
With this patch, all allocations are done using the code in
mm/vmalloc.c, though we use the low level __get_vm_area with
explicit start/stop constraints in order to manage separate
areas for vmalloc/vmap, ioremap, and PCI IOs.
This greatly simplifies a lot of things, as you can see in the
diffstat of that patch :-)
A new pair of functions pcibios_map/unmap_io_space() now replace
all of the previous code that used to manipulate PCI IOs space.
The allocation is done at mapping time, which is now called from
scan_phb's, just before the devices are probed (instead of after,
which is by itself a bug fix). The only other caller is the PCI
hotplug code for hot adding PCI-PCI bridges (slots).
imalloc is gone, as is the "sub-allocation" thing, but I do beleive
that hotplug should still work in the sense that the space allocation
is always done by the PHB, but if you unmap a child bus of this PHB
(which seems to be possible), then the code should properly tear
down all the HPTE mappings for that area of the PHB allocated IO space.
I now always reserve the first 64K of IO space for the bridge with
the ISA bus on it. I have moved the code for tracking ISA in a separate
file which should also make it smarter if we ever are capable of
hot unplugging or re-plugging an ISA bridge.
This should have a side effect on platforms like powermac where VGA IOs
will no longer work. This is done on purpose though as they would have
worked semi-randomly before. The idea at this point is to isolate drivers
that might need to access those and fix them by providing a proper
function to obtain an offset to the legacy IOs of a given bus.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
2007-06-04 13:15:36 +08:00
|
|
|
#define PGTABLE_RANGE (ASM_CONST(1) << PGTABLE_EADDR_SIZE)
|
2007-04-30 14:30:56 +08:00
|
|
|
|
|
|
|
#if TASK_SIZE_USER64 > PGTABLE_RANGE
|
|
|
|
#error TASK_SIZE_USER64 exceeds pagetable range
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if TASK_SIZE_USER64 > (1UL << (USER_ESID_BITS + SID_SHIFT))
|
|
|
|
#error TASK_SIZE_USER64 exceeds user VSID range
|
|
|
|
#endif
|
|
|
|
|
[POWERPC] Rewrite IO allocation & mapping on powerpc64
This rewrites pretty much from scratch the handling of MMIO and PIO
space allocations on powerpc64. The main goals are:
- Get rid of imalloc and use more common code where possible
- Simplify the current mess so that PIO space is allocated and
mapped in a single place for PCI bridges
- Handle allocation constraints of PIO for all bridges including
hot plugged ones within the 2GB space reserved for IO ports,
so that devices on hotplugged busses will now work with drivers
that assume IO ports fit in an int.
- Cleanup and separate tracking of the ISA space in the reserved
low 64K of IO space. No ISA -> Nothing mapped there.
I booted a cell blade with IDE on PIO and MMIO and a dual G5 so
far, that's it :-)
With this patch, all allocations are done using the code in
mm/vmalloc.c, though we use the low level __get_vm_area with
explicit start/stop constraints in order to manage separate
areas for vmalloc/vmap, ioremap, and PCI IOs.
This greatly simplifies a lot of things, as you can see in the
diffstat of that patch :-)
A new pair of functions pcibios_map/unmap_io_space() now replace
all of the previous code that used to manipulate PCI IOs space.
The allocation is done at mapping time, which is now called from
scan_phb's, just before the devices are probed (instead of after,
which is by itself a bug fix). The only other caller is the PCI
hotplug code for hot adding PCI-PCI bridges (slots).
imalloc is gone, as is the "sub-allocation" thing, but I do beleive
that hotplug should still work in the sense that the space allocation
is always done by the PHB, but if you unmap a child bus of this PHB
(which seems to be possible), then the code should properly tear
down all the HPTE mappings for that area of the PHB allocated IO space.
I now always reserve the first 64K of IO space for the bridge with
the ISA bus on it. I have moved the code for tracking ISA in a separate
file which should also make it smarter if we ever are capable of
hot unplugging or re-plugging an ISA bridge.
This should have a side effect on platforms like powermac where VGA IOs
will no longer work. This is done on purpose though as they would have
worked semi-randomly before. The idea at this point is to isolate drivers
that might need to access those and fix them by providing a proper
function to obtain an offset to the legacy IOs of a given bus.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
2007-06-04 13:15:36 +08:00
|
|
|
|
2007-04-30 14:30:56 +08:00
|
|
|
/*
|
|
|
|
* Define the address range of the vmalloc VM area.
|
|
|
|
*/
|
|
|
|
#define VMALLOC_START ASM_CONST(0xD000000000000000)
|
[POWERPC] Rewrite IO allocation & mapping on powerpc64
This rewrites pretty much from scratch the handling of MMIO and PIO
space allocations on powerpc64. The main goals are:
- Get rid of imalloc and use more common code where possible
- Simplify the current mess so that PIO space is allocated and
mapped in a single place for PCI bridges
- Handle allocation constraints of PIO for all bridges including
hot plugged ones within the 2GB space reserved for IO ports,
so that devices on hotplugged busses will now work with drivers
that assume IO ports fit in an int.
- Cleanup and separate tracking of the ISA space in the reserved
low 64K of IO space. No ISA -> Nothing mapped there.
I booted a cell blade with IDE on PIO and MMIO and a dual G5 so
far, that's it :-)
With this patch, all allocations are done using the code in
mm/vmalloc.c, though we use the low level __get_vm_area with
explicit start/stop constraints in order to manage separate
areas for vmalloc/vmap, ioremap, and PCI IOs.
This greatly simplifies a lot of things, as you can see in the
diffstat of that patch :-)
A new pair of functions pcibios_map/unmap_io_space() now replace
all of the previous code that used to manipulate PCI IOs space.
The allocation is done at mapping time, which is now called from
scan_phb's, just before the devices are probed (instead of after,
which is by itself a bug fix). The only other caller is the PCI
hotplug code for hot adding PCI-PCI bridges (slots).
imalloc is gone, as is the "sub-allocation" thing, but I do beleive
that hotplug should still work in the sense that the space allocation
is always done by the PHB, but if you unmap a child bus of this PHB
(which seems to be possible), then the code should properly tear
down all the HPTE mappings for that area of the PHB allocated IO space.
I now always reserve the first 64K of IO space for the bridge with
the ISA bus on it. I have moved the code for tracking ISA in a separate
file which should also make it smarter if we ever are capable of
hot unplugging or re-plugging an ISA bridge.
This should have a side effect on platforms like powermac where VGA IOs
will no longer work. This is done on purpose though as they would have
worked semi-randomly before. The idea at this point is to isolate drivers
that might need to access those and fix them by providing a proper
function to obtain an offset to the legacy IOs of a given bus.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
2007-06-04 13:15:36 +08:00
|
|
|
#define VMALLOC_SIZE (PGTABLE_RANGE >> 1)
|
2007-04-30 14:30:56 +08:00
|
|
|
#define VMALLOC_END (VMALLOC_START + VMALLOC_SIZE)
|
|
|
|
|
|
|
|
/*
|
[POWERPC] Rewrite IO allocation & mapping on powerpc64
This rewrites pretty much from scratch the handling of MMIO and PIO
space allocations on powerpc64. The main goals are:
- Get rid of imalloc and use more common code where possible
- Simplify the current mess so that PIO space is allocated and
mapped in a single place for PCI bridges
- Handle allocation constraints of PIO for all bridges including
hot plugged ones within the 2GB space reserved for IO ports,
so that devices on hotplugged busses will now work with drivers
that assume IO ports fit in an int.
- Cleanup and separate tracking of the ISA space in the reserved
low 64K of IO space. No ISA -> Nothing mapped there.
I booted a cell blade with IDE on PIO and MMIO and a dual G5 so
far, that's it :-)
With this patch, all allocations are done using the code in
mm/vmalloc.c, though we use the low level __get_vm_area with
explicit start/stop constraints in order to manage separate
areas for vmalloc/vmap, ioremap, and PCI IOs.
This greatly simplifies a lot of things, as you can see in the
diffstat of that patch :-)
A new pair of functions pcibios_map/unmap_io_space() now replace
all of the previous code that used to manipulate PCI IOs space.
The allocation is done at mapping time, which is now called from
scan_phb's, just before the devices are probed (instead of after,
which is by itself a bug fix). The only other caller is the PCI
hotplug code for hot adding PCI-PCI bridges (slots).
imalloc is gone, as is the "sub-allocation" thing, but I do beleive
that hotplug should still work in the sense that the space allocation
is always done by the PHB, but if you unmap a child bus of this PHB
(which seems to be possible), then the code should properly tear
down all the HPTE mappings for that area of the PHB allocated IO space.
I now always reserve the first 64K of IO space for the bridge with
the ISA bus on it. I have moved the code for tracking ISA in a separate
file which should also make it smarter if we ever are capable of
hot unplugging or re-plugging an ISA bridge.
This should have a side effect on platforms like powermac where VGA IOs
will no longer work. This is done on purpose though as they would have
worked semi-randomly before. The idea at this point is to isolate drivers
that might need to access those and fix them by providing a proper
function to obtain an offset to the legacy IOs of a given bus.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
2007-06-04 13:15:36 +08:00
|
|
|
* Define the address ranges for MMIO and IO space :
|
|
|
|
*
|
|
|
|
* ISA_IO_BASE = VMALLOC_END, 64K reserved area
|
|
|
|
* PHB_IO_BASE = ISA_IO_BASE + 64K to ISA_IO_BASE + 2G, PHB IO spaces
|
|
|
|
* IOREMAP_BASE = ISA_IO_BASE + 2G to VMALLOC_START + PGTABLE_RANGE
|
2007-04-30 14:30:56 +08:00
|
|
|
*/
|
[POWERPC] Rewrite IO allocation & mapping on powerpc64
This rewrites pretty much from scratch the handling of MMIO and PIO
space allocations on powerpc64. The main goals are:
- Get rid of imalloc and use more common code where possible
- Simplify the current mess so that PIO space is allocated and
mapped in a single place for PCI bridges
- Handle allocation constraints of PIO for all bridges including
hot plugged ones within the 2GB space reserved for IO ports,
so that devices on hotplugged busses will now work with drivers
that assume IO ports fit in an int.
- Cleanup and separate tracking of the ISA space in the reserved
low 64K of IO space. No ISA -> Nothing mapped there.
I booted a cell blade with IDE on PIO and MMIO and a dual G5 so
far, that's it :-)
With this patch, all allocations are done using the code in
mm/vmalloc.c, though we use the low level __get_vm_area with
explicit start/stop constraints in order to manage separate
areas for vmalloc/vmap, ioremap, and PCI IOs.
This greatly simplifies a lot of things, as you can see in the
diffstat of that patch :-)
A new pair of functions pcibios_map/unmap_io_space() now replace
all of the previous code that used to manipulate PCI IOs space.
The allocation is done at mapping time, which is now called from
scan_phb's, just before the devices are probed (instead of after,
which is by itself a bug fix). The only other caller is the PCI
hotplug code for hot adding PCI-PCI bridges (slots).
imalloc is gone, as is the "sub-allocation" thing, but I do beleive
that hotplug should still work in the sense that the space allocation
is always done by the PHB, but if you unmap a child bus of this PHB
(which seems to be possible), then the code should properly tear
down all the HPTE mappings for that area of the PHB allocated IO space.
I now always reserve the first 64K of IO space for the bridge with
the ISA bus on it. I have moved the code for tracking ISA in a separate
file which should also make it smarter if we ever are capable of
hot unplugging or re-plugging an ISA bridge.
This should have a side effect on platforms like powermac where VGA IOs
will no longer work. This is done on purpose though as they would have
worked semi-randomly before. The idea at this point is to isolate drivers
that might need to access those and fix them by providing a proper
function to obtain an offset to the legacy IOs of a given bus.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
2007-06-04 13:15:36 +08:00
|
|
|
#define FULL_IO_SIZE 0x80000000ul
|
|
|
|
#define ISA_IO_BASE (VMALLOC_END)
|
|
|
|
#define ISA_IO_END (VMALLOC_END + 0x10000ul)
|
|
|
|
#define PHB_IO_BASE (ISA_IO_END)
|
|
|
|
#define PHB_IO_END (VMALLOC_END + FULL_IO_SIZE)
|
|
|
|
#define IOREMAP_BASE (PHB_IO_END)
|
|
|
|
#define IOREMAP_END (VMALLOC_START + PGTABLE_RANGE)
|
2007-04-30 14:30:56 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Region IDs
|
|
|
|
*/
|
|
|
|
#define REGION_SHIFT 60UL
|
|
|
|
#define REGION_MASK (0xfUL << REGION_SHIFT)
|
|
|
|
#define REGION_ID(ea) (((unsigned long)(ea)) >> REGION_SHIFT)
|
|
|
|
|
|
|
|
#define VMALLOC_REGION_ID (REGION_ID(VMALLOC_START))
|
|
|
|
#define KERNEL_REGION_ID (REGION_ID(PAGE_OFFSET))
|
|
|
|
#define USER_REGION_ID (0UL)
|
|
|
|
|
2007-10-16 16:24:17 +08:00
|
|
|
/*
|
|
|
|
* Defines the address of the vmemap area, in the top 16th of the
|
|
|
|
* kernel region.
|
|
|
|
*/
|
|
|
|
#define VMEMMAP_BASE (ASM_CONST(CONFIG_KERNEL_START) + \
|
|
|
|
(0xfUL << (REGION_SHIFT - 4)))
|
|
|
|
#define vmemmap ((struct page *)VMEMMAP_BASE)
|
|
|
|
|
2007-04-30 14:30:56 +08:00
|
|
|
/*
|
|
|
|
* Common bits in a linux-style PTE. These match the bits in the
|
|
|
|
* (hardware-defined) PowerPC PTE as closely as possible. Additional
|
|
|
|
* bits may be defined in pgtable-*.h
|
|
|
|
*/
|
|
|
|
#define _PAGE_PRESENT 0x0001 /* software: pte contains a translation */
|
|
|
|
#define _PAGE_USER 0x0002 /* matches one of the PP bits */
|
|
|
|
#define _PAGE_FILE 0x0002 /* (!present only) software: pte holds file offset */
|
|
|
|
#define _PAGE_EXEC 0x0004 /* No execute on POWER4 and newer (we invert) */
|
|
|
|
#define _PAGE_GUARDED 0x0008
|
|
|
|
#define _PAGE_COHERENT 0x0010 /* M: enforce memory coherence (SMP systems) */
|
|
|
|
#define _PAGE_NO_CACHE 0x0020 /* I: cache inhibit */
|
|
|
|
#define _PAGE_WRITETHRU 0x0040 /* W: cache write-through */
|
|
|
|
#define _PAGE_DIRTY 0x0080 /* C: page changed */
|
|
|
|
#define _PAGE_ACCESSED 0x0100 /* R: page referenced */
|
|
|
|
#define _PAGE_RW 0x0200 /* software: user write access allowed */
|
|
|
|
#define _PAGE_HASHPTE 0x0400 /* software: pte has an associated HPTE */
|
|
|
|
#define _PAGE_BUSY 0x0800 /* software: PTE & hash are busy */
|
|
|
|
|
|
|
|
#define _PAGE_BASE (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_COHERENT)
|
|
|
|
|
|
|
|
#define _PAGE_WRENABLE (_PAGE_RW | _PAGE_DIRTY)
|
|
|
|
|
|
|
|
/* __pgprot defined in asm-powerpc/page.h */
|
|
|
|
#define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
|
|
|
|
|
|
|
|
#define PAGE_SHARED __pgprot(_PAGE_BASE | _PAGE_RW | _PAGE_USER)
|
|
|
|
#define PAGE_SHARED_X __pgprot(_PAGE_BASE | _PAGE_RW | _PAGE_USER | _PAGE_EXEC)
|
|
|
|
#define PAGE_COPY __pgprot(_PAGE_BASE | _PAGE_USER)
|
|
|
|
#define PAGE_COPY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
|
|
|
|
#define PAGE_READONLY __pgprot(_PAGE_BASE | _PAGE_USER)
|
|
|
|
#define PAGE_READONLY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
|
|
|
|
#define PAGE_KERNEL __pgprot(_PAGE_BASE | _PAGE_WRENABLE)
|
|
|
|
#define PAGE_KERNEL_CI __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
|
|
|
|
_PAGE_WRENABLE | _PAGE_NO_CACHE | _PAGE_GUARDED)
|
|
|
|
#define PAGE_KERNEL_EXEC __pgprot(_PAGE_BASE | _PAGE_WRENABLE | _PAGE_EXEC)
|
|
|
|
|
|
|
|
#define PAGE_AGP __pgprot(_PAGE_BASE | _PAGE_WRENABLE | _PAGE_NO_CACHE)
|
|
|
|
#define HAVE_PAGE_AGP
|
|
|
|
|
|
|
|
/* PTEIDX nibble */
|
|
|
|
#define _PTEIDX_SECONDARY 0x8
|
|
|
|
#define _PTEIDX_GROUP_IX 0x7
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* POWER4 and newer have per page execute protection, older chips can only
|
|
|
|
* do this on a segment (256MB) basis.
|
|
|
|
*
|
|
|
|
* Also, write permissions imply read permissions.
|
|
|
|
* This is the closest we can get..
|
|
|
|
*
|
|
|
|
* Note due to the way vm flags are laid out, the bits are XWR
|
|
|
|
*/
|
|
|
|
#define __P000 PAGE_NONE
|
|
|
|
#define __P001 PAGE_READONLY
|
|
|
|
#define __P010 PAGE_COPY
|
|
|
|
#define __P011 PAGE_COPY
|
|
|
|
#define __P100 PAGE_READONLY_X
|
|
|
|
#define __P101 PAGE_READONLY_X
|
|
|
|
#define __P110 PAGE_COPY_X
|
|
|
|
#define __P111 PAGE_COPY_X
|
|
|
|
|
|
|
|
#define __S000 PAGE_NONE
|
|
|
|
#define __S001 PAGE_READONLY
|
|
|
|
#define __S010 PAGE_SHARED
|
|
|
|
#define __S011 PAGE_SHARED
|
|
|
|
#define __S100 PAGE_READONLY_X
|
|
|
|
#define __S101 PAGE_READONLY_X
|
|
|
|
#define __S110 PAGE_SHARED_X
|
|
|
|
#define __S111 PAGE_SHARED_X
|
|
|
|
|
|
|
|
#ifdef CONFIG_HUGETLB_PAGE
|
|
|
|
|
|
|
|
#define HAVE_ARCH_UNMAPPED_AREA
|
|
|
|
#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef __ASSEMBLY__
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Conversion functions: convert a page and protection to a page entry,
|
|
|
|
* and a page entry and page directory to the page they refer to.
|
|
|
|
*
|
|
|
|
* mk_pte takes a (struct page *) as input
|
|
|
|
*/
|
|
|
|
#define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot))
|
|
|
|
|
|
|
|
static inline pte_t pfn_pte(unsigned long pfn, pgprot_t pgprot)
|
|
|
|
{
|
|
|
|
pte_t pte;
|
|
|
|
|
|
|
|
|
|
|
|
pte_val(pte) = (pfn << PTE_RPN_SHIFT) | pgprot_val(pgprot);
|
|
|
|
return pte;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define pte_modify(_pte, newprot) \
|
|
|
|
(__pte((pte_val(_pte) & _PAGE_CHG_MASK) | pgprot_val(newprot)))
|
|
|
|
|
|
|
|
#define pte_none(pte) ((pte_val(pte) & ~_PAGE_HPTEFLAGS) == 0)
|
|
|
|
#define pte_present(pte) (pte_val(pte) & _PAGE_PRESENT)
|
|
|
|
|
|
|
|
/* pte_clear moved to later in this file */
|
|
|
|
|
|
|
|
#define pte_pfn(x) ((unsigned long)((pte_val(x)>>PTE_RPN_SHIFT)))
|
|
|
|
#define pte_page(x) pfn_to_page(pte_pfn(x))
|
|
|
|
|
|
|
|
#define PMD_BAD_BITS (PTE_TABLE_SIZE-1)
|
|
|
|
#define PUD_BAD_BITS (PMD_TABLE_SIZE-1)
|
|
|
|
|
|
|
|
#define pmd_set(pmdp, pmdval) (pmd_val(*(pmdp)) = (pmdval))
|
|
|
|
#define pmd_none(pmd) (!pmd_val(pmd))
|
|
|
|
#define pmd_bad(pmd) (!is_kernel_addr(pmd_val(pmd)) \
|
|
|
|
|| (pmd_val(pmd) & PMD_BAD_BITS))
|
|
|
|
#define pmd_present(pmd) (pmd_val(pmd) != 0)
|
|
|
|
#define pmd_clear(pmdp) (pmd_val(*(pmdp)) = 0)
|
|
|
|
#define pmd_page_vaddr(pmd) (pmd_val(pmd) & ~PMD_MASKED_BITS)
|
|
|
|
#define pmd_page(pmd) virt_to_page(pmd_page_vaddr(pmd))
|
|
|
|
|
|
|
|
#define pud_set(pudp, pudval) (pud_val(*(pudp)) = (pudval))
|
|
|
|
#define pud_none(pud) (!pud_val(pud))
|
|
|
|
#define pud_bad(pud) (!is_kernel_addr(pud_val(pud)) \
|
|
|
|
|| (pud_val(pud) & PUD_BAD_BITS))
|
|
|
|
#define pud_present(pud) (pud_val(pud) != 0)
|
|
|
|
#define pud_clear(pudp) (pud_val(*(pudp)) = 0)
|
|
|
|
#define pud_page_vaddr(pud) (pud_val(pud) & ~PUD_MASKED_BITS)
|
|
|
|
#define pud_page(pud) virt_to_page(pud_page_vaddr(pud))
|
|
|
|
|
|
|
|
#define pgd_set(pgdp, pudp) ({pgd_val(*(pgdp)) = (unsigned long)(pudp);})
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find an entry in a page-table-directory. We combine the address region
|
|
|
|
* (the high order N bits) and the pgd portion of the address.
|
|
|
|
*/
|
|
|
|
/* to avoid overflow in free_pgtables we don't use PTRS_PER_PGD here */
|
|
|
|
#define pgd_index(address) (((address) >> (PGDIR_SHIFT)) & 0x1ff)
|
|
|
|
|
|
|
|
#define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address))
|
|
|
|
|
|
|
|
#define pmd_offset(pudp,addr) \
|
|
|
|
(((pmd_t *) pud_page_vaddr(*(pudp))) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)))
|
|
|
|
|
|
|
|
#define pte_offset_kernel(dir,addr) \
|
|
|
|
(((pte_t *) pmd_page_vaddr(*(dir))) + (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
|
|
|
|
|
|
|
|
#define pte_offset_map(dir,addr) pte_offset_kernel((dir), (addr))
|
|
|
|
#define pte_offset_map_nested(dir,addr) pte_offset_kernel((dir), (addr))
|
|
|
|
#define pte_unmap(pte) do { } while(0)
|
|
|
|
#define pte_unmap_nested(pte) do { } while(0)
|
|
|
|
|
|
|
|
/* to find an entry in a kernel page-table-directory */
|
|
|
|
/* This now only contains the vmalloc pages */
|
|
|
|
#define pgd_offset_k(address) pgd_offset(&init_mm, address)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The following only work if pte_present() is true.
|
|
|
|
* Undefined behaviour if not..
|
|
|
|
*/
|
|
|
|
static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW;}
|
|
|
|
static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY;}
|
|
|
|
static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED;}
|
|
|
|
static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE;}
|
mm: introduce pte_special pte bit
s390 for one, cannot implement VM_MIXEDMAP with pfn_valid, due to their memory
model (which is more dynamic than most). Instead, they had proposed to
implement it with an additional path through vm_normal_page(), using a bit in
the pte to determine whether or not the page should be refcounted:
vm_normal_page()
{
...
if (unlikely(vma->vm_flags & (VM_PFNMAP|VM_MIXEDMAP))) {
if (vma->vm_flags & VM_MIXEDMAP) {
#ifdef s390
if (!mixedmap_refcount_pte(pte))
return NULL;
#else
if (!pfn_valid(pfn))
return NULL;
#endif
goto out;
}
...
}
This is fine, however if we are allowed to use a bit in the pte to determine
refcountedness, we can use that to _completely_ replace all the vma based
schemes. So instead of adding more cases to the already complex vma-based
scheme, we can have a clearly seperate and simple pte-based scheme (and get
slightly better code generation in the process):
vm_normal_page()
{
#ifdef s390
if (!mixedmap_refcount_pte(pte))
return NULL;
return pte_page(pte);
#else
...
#endif
}
And finally, we may rather make this concept usable by any architecture rather
than making it s390 only, so implement a new type of pte state for this.
Unfortunately the old vma based code must stay, because some architectures may
not be able to spare pte bits. This makes vm_normal_page a little bit more
ugly than we would like, but the 2 cases are clearly seperate.
So introduce a pte_special pte state, and use it in mm/memory.c. It is
currently a noop for all architectures, so this doesn't actually result in any
compiled code changes to mm/memory.o.
BTW:
I haven't put vm_normal_page() into arch code as-per an earlier suggestion.
The reason is that, regardless of where vm_normal_page is actually
implemented, the *abstraction* is still exactly the same. Also, while it
depends on whether the architecture has pte_special or not, that is the
only two possible cases, and it really isn't an arch specific function --
the role of the arch code should be to provide primitive functions and
accessors with which to build the core code; pte_special does that. We do
not want architectures to know or care about vm_normal_page itself, and
we definitely don't want them being able to invent something new there
out of sight of mm/ code. If we made vm_normal_page an arch function, then
we have to make vm_insert_mixed (next patch) an arch function too. So I
don't think moving it to arch code fundamentally improves any abstractions,
while it does practically make the code more difficult to follow, for both
mm and arch developers, and easier to misuse.
[akpm@linux-foundation.org: build fix]
Signed-off-by: Nick Piggin <npiggin@suse.de>
Acked-by: Carsten Otte <cotte@de.ibm.com>
Cc: Jared Hulbert <jaredeh@gmail.com>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-04-28 17:13:00 +08:00
|
|
|
static inline int pte_special(pte_t pte) { return 0; }
|
2007-04-30 14:30:56 +08:00
|
|
|
|
|
|
|
static inline void pte_uncache(pte_t pte) { pte_val(pte) |= _PAGE_NO_CACHE; }
|
|
|
|
static inline void pte_cache(pte_t pte) { pte_val(pte) &= ~_PAGE_NO_CACHE; }
|
|
|
|
|
|
|
|
static inline pte_t pte_wrprotect(pte_t pte) {
|
|
|
|
pte_val(pte) &= ~(_PAGE_RW); return pte; }
|
|
|
|
static inline pte_t pte_mkclean(pte_t pte) {
|
|
|
|
pte_val(pte) &= ~(_PAGE_DIRTY); return pte; }
|
|
|
|
static inline pte_t pte_mkold(pte_t pte) {
|
|
|
|
pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
|
|
|
|
static inline pte_t pte_mkwrite(pte_t pte) {
|
|
|
|
pte_val(pte) |= _PAGE_RW; return pte; }
|
|
|
|
static inline pte_t pte_mkdirty(pte_t pte) {
|
|
|
|
pte_val(pte) |= _PAGE_DIRTY; return pte; }
|
|
|
|
static inline pte_t pte_mkyoung(pte_t pte) {
|
|
|
|
pte_val(pte) |= _PAGE_ACCESSED; return pte; }
|
|
|
|
static inline pte_t pte_mkhuge(pte_t pte) {
|
|
|
|
return pte; }
|
mm: introduce pte_special pte bit
s390 for one, cannot implement VM_MIXEDMAP with pfn_valid, due to their memory
model (which is more dynamic than most). Instead, they had proposed to
implement it with an additional path through vm_normal_page(), using a bit in
the pte to determine whether or not the page should be refcounted:
vm_normal_page()
{
...
if (unlikely(vma->vm_flags & (VM_PFNMAP|VM_MIXEDMAP))) {
if (vma->vm_flags & VM_MIXEDMAP) {
#ifdef s390
if (!mixedmap_refcount_pte(pte))
return NULL;
#else
if (!pfn_valid(pfn))
return NULL;
#endif
goto out;
}
...
}
This is fine, however if we are allowed to use a bit in the pte to determine
refcountedness, we can use that to _completely_ replace all the vma based
schemes. So instead of adding more cases to the already complex vma-based
scheme, we can have a clearly seperate and simple pte-based scheme (and get
slightly better code generation in the process):
vm_normal_page()
{
#ifdef s390
if (!mixedmap_refcount_pte(pte))
return NULL;
return pte_page(pte);
#else
...
#endif
}
And finally, we may rather make this concept usable by any architecture rather
than making it s390 only, so implement a new type of pte state for this.
Unfortunately the old vma based code must stay, because some architectures may
not be able to spare pte bits. This makes vm_normal_page a little bit more
ugly than we would like, but the 2 cases are clearly seperate.
So introduce a pte_special pte state, and use it in mm/memory.c. It is
currently a noop for all architectures, so this doesn't actually result in any
compiled code changes to mm/memory.o.
BTW:
I haven't put vm_normal_page() into arch code as-per an earlier suggestion.
The reason is that, regardless of where vm_normal_page is actually
implemented, the *abstraction* is still exactly the same. Also, while it
depends on whether the architecture has pte_special or not, that is the
only two possible cases, and it really isn't an arch specific function --
the role of the arch code should be to provide primitive functions and
accessors with which to build the core code; pte_special does that. We do
not want architectures to know or care about vm_normal_page itself, and
we definitely don't want them being able to invent something new there
out of sight of mm/ code. If we made vm_normal_page an arch function, then
we have to make vm_insert_mixed (next patch) an arch function too. So I
don't think moving it to arch code fundamentally improves any abstractions,
while it does practically make the code more difficult to follow, for both
mm and arch developers, and easier to misuse.
[akpm@linux-foundation.org: build fix]
Signed-off-by: Nick Piggin <npiggin@suse.de>
Acked-by: Carsten Otte <cotte@de.ibm.com>
Cc: Jared Hulbert <jaredeh@gmail.com>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-04-28 17:13:00 +08:00
|
|
|
static inline pte_t pte_mkspecial(pte_t pte) {
|
|
|
|
return pte; }
|
2007-04-30 14:30:56 +08:00
|
|
|
|
|
|
|
/* Atomic PTE updates */
|
|
|
|
static inline unsigned long pte_update(struct mm_struct *mm,
|
|
|
|
unsigned long addr,
|
|
|
|
pte_t *ptep, unsigned long clr,
|
|
|
|
int huge)
|
|
|
|
{
|
|
|
|
unsigned long old, tmp;
|
|
|
|
|
|
|
|
__asm__ __volatile__(
|
|
|
|
"1: ldarx %0,0,%3 # pte_update\n\
|
|
|
|
andi. %1,%0,%6\n\
|
|
|
|
bne- 1b \n\
|
|
|
|
andc %1,%0,%4 \n\
|
|
|
|
stdcx. %1,0,%3 \n\
|
|
|
|
bne- 1b"
|
|
|
|
: "=&r" (old), "=&r" (tmp), "=m" (*ptep)
|
|
|
|
: "r" (ptep), "r" (clr), "m" (*ptep), "i" (_PAGE_BUSY)
|
|
|
|
: "cc" );
|
|
|
|
|
|
|
|
if (old & _PAGE_HASHPTE)
|
|
|
|
hpte_need_flush(mm, addr, ptep, old, huge);
|
|
|
|
return old;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int __ptep_test_and_clear_young(struct mm_struct *mm,
|
|
|
|
unsigned long addr, pte_t *ptep)
|
|
|
|
{
|
|
|
|
unsigned long old;
|
|
|
|
|
|
|
|
if ((pte_val(*ptep) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0)
|
|
|
|
return 0;
|
|
|
|
old = pte_update(mm, addr, ptep, _PAGE_ACCESSED, 0);
|
|
|
|
return (old & _PAGE_ACCESSED) != 0;
|
|
|
|
}
|
|
|
|
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
|
|
|
|
#define ptep_test_and_clear_young(__vma, __addr, __ptep) \
|
|
|
|
({ \
|
|
|
|
int __r; \
|
|
|
|
__r = __ptep_test_and_clear_young((__vma)->vm_mm, __addr, __ptep); \
|
|
|
|
__r; \
|
|
|
|
})
|
|
|
|
|
|
|
|
#define __HAVE_ARCH_PTEP_SET_WRPROTECT
|
|
|
|
static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
|
|
|
|
pte_t *ptep)
|
|
|
|
{
|
|
|
|
unsigned long old;
|
|
|
|
|
|
|
|
if ((pte_val(*ptep) & _PAGE_RW) == 0)
|
|
|
|
return;
|
|
|
|
old = pte_update(mm, addr, ptep, _PAGE_RW, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We currently remove entries from the hashtable regardless of whether
|
|
|
|
* the entry was young or dirty. The generic routines only flush if the
|
|
|
|
* entry was young or dirty which is not good enough.
|
|
|
|
*
|
|
|
|
* We should be more intelligent about this but for the moment we override
|
|
|
|
* these functions and force a tlb flush unconditionally
|
|
|
|
*/
|
|
|
|
#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
|
|
|
|
#define ptep_clear_flush_young(__vma, __address, __ptep) \
|
|
|
|
({ \
|
|
|
|
int __young = __ptep_test_and_clear_young((__vma)->vm_mm, __address, \
|
|
|
|
__ptep); \
|
|
|
|
__young; \
|
|
|
|
})
|
|
|
|
|
|
|
|
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
|
|
|
|
static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
|
|
|
|
unsigned long addr, pte_t *ptep)
|
|
|
|
{
|
|
|
|
unsigned long old = pte_update(mm, addr, ptep, ~0UL, 0);
|
|
|
|
return __pte(old);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void pte_clear(struct mm_struct *mm, unsigned long addr,
|
|
|
|
pte_t * ptep)
|
|
|
|
{
|
|
|
|
pte_update(mm, addr, ptep, ~0UL, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* set_pte stores a linux PTE into the linux page table.
|
|
|
|
*/
|
|
|
|
static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
|
|
|
|
pte_t *ptep, pte_t pte)
|
|
|
|
{
|
|
|
|
if (pte_present(*ptep))
|
|
|
|
pte_clear(mm, addr, ptep);
|
|
|
|
pte = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS);
|
|
|
|
*ptep = pte;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the dirty and/or accessed bits atomically in a linux PTE, this
|
|
|
|
* function doesn't need to flush the hash entry
|
|
|
|
*/
|
|
|
|
#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
|
|
|
|
static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty)
|
|
|
|
{
|
|
|
|
unsigned long bits = pte_val(entry) &
|
|
|
|
(_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC);
|
|
|
|
unsigned long old, tmp;
|
|
|
|
|
|
|
|
__asm__ __volatile__(
|
|
|
|
"1: ldarx %0,0,%4\n\
|
|
|
|
andi. %1,%0,%6\n\
|
|
|
|
bne- 1b \n\
|
|
|
|
or %0,%3,%0\n\
|
|
|
|
stdcx. %0,0,%4\n\
|
|
|
|
bne- 1b"
|
|
|
|
:"=&r" (old), "=&r" (tmp), "=m" (*ptep)
|
|
|
|
:"r" (bits), "r" (ptep), "m" (*ptep), "i" (_PAGE_BUSY)
|
|
|
|
:"cc");
|
|
|
|
}
|
|
|
|
#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
|
2007-06-17 01:16:12 +08:00
|
|
|
({ \
|
|
|
|
int __changed = !pte_same(*(__ptep), __entry); \
|
|
|
|
if (__changed) { \
|
|
|
|
__ptep_set_access_flags(__ptep, __entry, __dirty); \
|
|
|
|
flush_tlb_page_nohash(__vma, __address); \
|
|
|
|
} \
|
|
|
|
__changed; \
|
|
|
|
})
|
2007-04-30 14:30:56 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Macro to mark a page protection value as "uncacheable".
|
|
|
|
*/
|
|
|
|
#define pgprot_noncached(prot) (__pgprot(pgprot_val(prot) | _PAGE_NO_CACHE | _PAGE_GUARDED))
|
|
|
|
|
|
|
|
struct file;
|
|
|
|
extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
|
|
|
|
unsigned long size, pgprot_t vma_prot);
|
|
|
|
#define __HAVE_PHYS_MEM_ACCESS_PROT
|
|
|
|
|
|
|
|
#define __HAVE_ARCH_PTE_SAME
|
|
|
|
#define pte_same(A,B) (((pte_val(A) ^ pte_val(B)) & ~_PAGE_HPTEFLAGS) == 0)
|
|
|
|
|
|
|
|
#define pte_ERROR(e) \
|
|
|
|
printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
|
|
|
|
#define pmd_ERROR(e) \
|
|
|
|
printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
|
|
|
|
#define pgd_ERROR(e) \
|
|
|
|
printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
|
|
|
|
|
|
|
|
/* Encode and de-code a swap entry */
|
|
|
|
#define __swp_type(entry) (((entry).val >> 1) & 0x3f)
|
|
|
|
#define __swp_offset(entry) ((entry).val >> 8)
|
|
|
|
#define __swp_entry(type, offset) ((swp_entry_t){((type)<< 1)|((offset)<<8)})
|
|
|
|
#define __pte_to_swp_entry(pte) ((swp_entry_t){pte_val(pte) >> PTE_RPN_SHIFT})
|
|
|
|
#define __swp_entry_to_pte(x) ((pte_t) { (x).val << PTE_RPN_SHIFT })
|
|
|
|
#define pte_to_pgoff(pte) (pte_val(pte) >> PTE_RPN_SHIFT)
|
|
|
|
#define pgoff_to_pte(off) ((pte_t) {((off) << PTE_RPN_SHIFT)|_PAGE_FILE})
|
|
|
|
#define PTE_FILE_MAX_BITS (BITS_PER_LONG - PTE_RPN_SHIFT)
|
|
|
|
|
|
|
|
void pgtable_cache_init(void);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* find_linux_pte returns the address of a linux pte for a given
|
|
|
|
* effective address and directory. If not found, it returns zero.
|
|
|
|
*/static inline pte_t *find_linux_pte(pgd_t *pgdir, unsigned long ea)
|
|
|
|
{
|
|
|
|
pgd_t *pg;
|
|
|
|
pud_t *pu;
|
|
|
|
pmd_t *pm;
|
|
|
|
pte_t *pt = NULL;
|
|
|
|
|
|
|
|
pg = pgdir + pgd_index(ea);
|
|
|
|
if (!pgd_none(*pg)) {
|
|
|
|
pu = pud_offset(pg, ea);
|
|
|
|
if (!pud_none(*pu)) {
|
|
|
|
pm = pmd_offset(pu, ea);
|
|
|
|
if (pmd_present(*pm))
|
|
|
|
pt = pte_offset_kernel(pm, ea);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return pt;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* __ASSEMBLY__ */
|
|
|
|
|
|
|
|
#endif /* _ASM_POWERPC_PGTABLE_PPC64_H_ */
|