2007-04-30 06:30:56 +00: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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef CONFIG_PPC_64K_PAGES
|
2009-03-10 17:53:29 +00:00
|
|
|
#include <asm/pgtable-ppc64-64k.h>
|
2007-04-30 06:30:56 +00:00
|
|
|
#else
|
2009-03-10 17:53:29 +00:00
|
|
|
#include <asm/pgtable-ppc64-4k.h>
|
2007-04-30 06:30:56 +00:00
|
|
|
#endif
|
2013-06-20 09:00:15 +00:00
|
|
|
#include <asm/barrier.h>
|
2007-04-30 06:30:56 +00:00
|
|
|
|
|
|
|
#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 05:15:36 +00:00
|
|
|
#define PGTABLE_RANGE (ASM_CONST(1) << PGTABLE_EADDR_SIZE)
|
2007-04-30 06:30:56 +00:00
|
|
|
|
2013-06-20 09:00:14 +00:00
|
|
|
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
|
|
|
#define PMD_CACHE_INDEX (PMD_INDEX_SIZE + 1)
|
|
|
|
#else
|
|
|
|
#define PMD_CACHE_INDEX PMD_INDEX_SIZE
|
|
|
|
#endif
|
2007-04-30 06:30:56 +00:00
|
|
|
/*
|
2009-07-28 01:59:34 +00:00
|
|
|
* Define the address range of the kernel non-linear virtual area
|
2007-04-30 06:30:56 +00:00
|
|
|
*/
|
2009-07-28 01:59:34 +00:00
|
|
|
|
|
|
|
#ifdef CONFIG_PPC_BOOK3E
|
|
|
|
#define KERN_VIRT_START ASM_CONST(0x8000000000000000)
|
|
|
|
#else
|
|
|
|
#define KERN_VIRT_START ASM_CONST(0xD000000000000000)
|
|
|
|
#endif
|
2012-09-10 02:52:51 +00:00
|
|
|
#define KERN_VIRT_SIZE ASM_CONST(0x0000100000000000)
|
2007-04-30 06:30:56 +00:00
|
|
|
|
|
|
|
/*
|
2009-07-28 01:59:34 +00:00
|
|
|
* The vmalloc space starts at the beginning of that region, and
|
|
|
|
* occupies half of it on hash CPUs and a quarter of it on Book3E
|
2009-07-23 23:15:58 +00:00
|
|
|
* (we keep a quarter for the virtual memmap)
|
2009-07-28 01:59:34 +00:00
|
|
|
*/
|
|
|
|
#define VMALLOC_START KERN_VIRT_START
|
|
|
|
#ifdef CONFIG_PPC_BOOK3E
|
|
|
|
#define VMALLOC_SIZE (KERN_VIRT_SIZE >> 2)
|
|
|
|
#else
|
|
|
|
#define VMALLOC_SIZE (KERN_VIRT_SIZE >> 1)
|
|
|
|
#endif
|
|
|
|
#define VMALLOC_END (VMALLOC_START + VMALLOC_SIZE)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The second half of the kernel virtual space is used for IO mappings,
|
|
|
|
* it's itself carved into the PIO region (ISA and PHB IO space) and
|
|
|
|
* the ioremap space
|
[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 05:15:36 +00:00
|
|
|
*
|
2009-07-28 01:59:34 +00:00
|
|
|
* ISA_IO_BASE = KERN_IO_START, 64K reserved area
|
[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 05:15:36 +00:00
|
|
|
* 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 06:30:56 +00:00
|
|
|
*/
|
2009-07-28 01:59:34 +00:00
|
|
|
#define KERN_IO_START (KERN_VIRT_START + (KERN_VIRT_SIZE >> 1))
|
[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 05:15:36 +00:00
|
|
|
#define FULL_IO_SIZE 0x80000000ul
|
2009-07-28 01:59:34 +00:00
|
|
|
#define ISA_IO_BASE (KERN_IO_START)
|
|
|
|
#define ISA_IO_END (KERN_IO_START + 0x10000ul)
|
[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 05:15:36 +00:00
|
|
|
#define PHB_IO_BASE (ISA_IO_END)
|
2009-07-28 01:59:34 +00:00
|
|
|
#define PHB_IO_END (KERN_IO_START + FULL_IO_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 05:15:36 +00:00
|
|
|
#define IOREMAP_BASE (PHB_IO_END)
|
2009-07-28 01:59:34 +00:00
|
|
|
#define IOREMAP_END (KERN_VIRT_START + KERN_VIRT_SIZE)
|
|
|
|
|
2007-04-30 06:30:56 +00: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))
|
2009-07-23 23:15:58 +00:00
|
|
|
#define VMEMMAP_REGION_ID (0xfUL) /* Server only */
|
2007-04-30 06:30:56 +00:00
|
|
|
#define USER_REGION_ID (0UL)
|
|
|
|
|
2007-10-16 08:24:17 +00:00
|
|
|
/*
|
2009-07-28 01:59:34 +00:00
|
|
|
* Defines the address of the vmemap area, in its own region on
|
|
|
|
* hash table CPUs and after the vmalloc space on Book3E
|
2007-10-16 08:24:17 +00:00
|
|
|
*/
|
2009-07-28 01:59:34 +00:00
|
|
|
#ifdef CONFIG_PPC_BOOK3E
|
|
|
|
#define VMEMMAP_BASE VMALLOC_END
|
|
|
|
#define VMEMMAP_END KERN_IO_START
|
|
|
|
#else
|
[POWERPC] vmemmap fixes to use smaller pages
This changes vmemmap to use a different region (region 0xf) of the
address space, and to configure the page size of that region
dynamically at boot.
The problem with the current approach of always using 16M pages is that
it's not well suited to machines that have small amounts of memory such
as small partitions on pseries, or PS3's.
In fact, on the PS3, failure to allocate the 16M page backing vmmemmap
tends to prevent hotplugging the HV's "additional" memory, thus limiting
the available memory even more, from my experience down to something
like 80M total, which makes it really not very useable.
The logic used by my match to choose the vmemmap page size is:
- If 16M pages are available and there's 1G or more RAM at boot,
use that size.
- Else if 64K pages are available, use that
- Else use 4K pages
I've tested on a POWER6 (16M pages) and on an iSeries POWER3 (4K pages)
and it seems to work fine.
Note that I intend to change the way we organize the kernel regions &
SLBs so the actual region will change from 0xf back to something else at
one point, as I simplify the SLB miss handler, but that will be for a
later patch.
Signed-off-by: Paul Mackerras <paulus@samba.org>
2008-04-30 05:41:48 +00:00
|
|
|
#define VMEMMAP_BASE (VMEMMAP_REGION_ID << REGION_SHIFT)
|
2009-07-28 01:59:34 +00:00
|
|
|
#endif
|
[POWERPC] vmemmap fixes to use smaller pages
This changes vmemmap to use a different region (region 0xf) of the
address space, and to configure the page size of that region
dynamically at boot.
The problem with the current approach of always using 16M pages is that
it's not well suited to machines that have small amounts of memory such
as small partitions on pseries, or PS3's.
In fact, on the PS3, failure to allocate the 16M page backing vmmemmap
tends to prevent hotplugging the HV's "additional" memory, thus limiting
the available memory even more, from my experience down to something
like 80M total, which makes it really not very useable.
The logic used by my match to choose the vmemmap page size is:
- If 16M pages are available and there's 1G or more RAM at boot,
use that size.
- Else if 64K pages are available, use that
- Else use 4K pages
I've tested on a POWER6 (16M pages) and on an iSeries POWER3 (4K pages)
and it seems to work fine.
Note that I intend to change the way we organize the kernel regions &
SLBs so the actual region will change from 0xf back to something else at
one point, as I simplify the SLB miss handler, but that will be for a
later patch.
Signed-off-by: Paul Mackerras <paulus@samba.org>
2008-04-30 05:41:48 +00:00
|
|
|
#define vmemmap ((struct page *)VMEMMAP_BASE)
|
|
|
|
|
2007-10-16 08:24:17 +00:00
|
|
|
|
2007-04-30 06:30:56 +00:00
|
|
|
/*
|
2009-03-10 17:53:29 +00:00
|
|
|
* Include the PTE bits definitions
|
2007-04-30 06:30:56 +00:00
|
|
|
*/
|
2009-07-28 01:59:34 +00:00
|
|
|
#ifdef CONFIG_PPC_BOOK3S
|
2009-03-10 17:53:29 +00:00
|
|
|
#include <asm/pte-hash64.h>
|
2009-07-28 01:59:34 +00:00
|
|
|
#else
|
|
|
|
#include <asm/pte-book3e.h>
|
|
|
|
#endif
|
2009-03-19 19:34:09 +00:00
|
|
|
#include <asm/pte-common.h>
|
2009-03-10 17:53:29 +00:00
|
|
|
|
2008-09-03 03:12:05 +00:00
|
|
|
#ifdef CONFIG_PPC_MM_SLICES
|
2007-04-30 06:30:56 +00:00
|
|
|
#define HAVE_ARCH_UNMAPPED_AREA
|
|
|
|
#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
|
2008-09-03 03:12:05 +00:00
|
|
|
#endif /* CONFIG_PPC_MM_SLICES */
|
2007-04-30 06:30:56 +00:00
|
|
|
|
|
|
|
#ifndef __ASSEMBLY__
|
|
|
|
|
2009-03-10 17:53:29 +00:00
|
|
|
/*
|
|
|
|
* This is the default implementation of various PTE accessors, it's
|
|
|
|
* used in all cases except Book3S with 64K pages where we have a
|
|
|
|
* concept of sub-pages
|
|
|
|
*/
|
|
|
|
#ifndef __real_pte
|
|
|
|
|
|
|
|
#ifdef STRICT_MM_TYPECHECKS
|
|
|
|
#define __real_pte(e,p) ((real_pte_t){(e)})
|
|
|
|
#define __rpte_to_pte(r) ((r).pte)
|
|
|
|
#else
|
|
|
|
#define __real_pte(e,p) (e)
|
|
|
|
#define __rpte_to_pte(r) (__pte(r))
|
|
|
|
#endif
|
|
|
|
#define __rpte_to_hidx(r,index) (pte_val(__rpte_to_pte(r)) >> 12)
|
|
|
|
|
|
|
|
#define pte_iterate_hashed_subpages(rpte, psize, va, index, shift) \
|
|
|
|
do { \
|
|
|
|
index = 0; \
|
|
|
|
shift = mmu_psize_defs[psize].shift; \
|
|
|
|
|
|
|
|
#define pte_iterate_hashed_end() } while(0)
|
|
|
|
|
|
|
|
#ifdef CONFIG_PPC_HAS_HASH_64K
|
|
|
|
#define pte_pagesize_index(mm, addr, pte) get_slice_psize(mm, addr)
|
|
|
|
#else
|
|
|
|
#define pte_pagesize_index(mm, addr, pte) MMU_PAGE_4K
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif /* __real_pte */
|
|
|
|
|
|
|
|
|
2007-04-30 06:30:56 +00:00
|
|
|
/* pte_clear moved to later in this file */
|
|
|
|
|
|
|
|
#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)
|
2013-06-20 09:00:15 +00:00
|
|
|
extern struct page *pmd_page(pmd_t pmd);
|
2007-04-30 06:30:56 +00:00
|
|
|
|
|
|
|
#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.
|
|
|
|
*/
|
2013-04-28 09:37:28 +00:00
|
|
|
#define pgd_index(address) (((address) >> (PGDIR_SHIFT)) & (PTRS_PER_PGD - 1))
|
2007-04-30 06:30:56 +00:00
|
|
|
|
|
|
|
#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_unmap(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)
|
2012-09-10 02:52:57 +00:00
|
|
|
extern void hpte_need_flush(struct mm_struct *mm, unsigned long addr,
|
|
|
|
pte_t *ptep, unsigned long pte, int huge);
|
2007-04-30 06:30:56 +00: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)
|
|
|
|
{
|
2009-03-19 19:34:15 +00:00
|
|
|
#ifdef PTE_ATOMIC_UPDATES
|
2007-04-30 06:30:56 +00:00
|
|
|
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" );
|
2009-03-19 19:34:15 +00:00
|
|
|
#else
|
|
|
|
unsigned long old = pte_val(*ptep);
|
|
|
|
*ptep = __pte(old & ~clr);
|
|
|
|
#endif
|
powerpc/mm: Rework I$/D$ coherency (v3)
This patch reworks the way we do I and D cache coherency on PowerPC.
The "old" way was split in 3 different parts depending on the processor type:
- Hash with per-page exec support (64-bit and >= POWER4 only) does it
at hashing time, by preventing exec on unclean pages and cleaning pages
on exec faults.
- Everything without per-page exec support (32-bit hash, 8xx, and
64-bit < POWER4) does it for all page going to user space in update_mmu_cache().
- Embedded with per-page exec support does it from do_page_fault() on
exec faults, in a way similar to what the hash code does.
That leads to confusion, and bugs. For example, the method using update_mmu_cache()
is racy on SMP where another processor can see the new PTE and hash it in before
we have cleaned the cache, and then blow trying to execute. This is hard to hit but
I think it has bitten us in the past.
Also, it's inefficient for embedded where we always end up having to do at least
one more page fault.
This reworks the whole thing by moving the cache sync into two main call sites,
though we keep different behaviours depending on the HW capability. The call
sites are set_pte_at() which is now made out of line, and ptep_set_access_flags()
which joins the former in pgtable.c
The base idea for Embedded with per-page exec support, is that we now do the
flush at set_pte_at() time when coming from an exec fault, which allows us
to avoid the double fault problem completely (we can even improve the situation
more by implementing TLB preload in update_mmu_cache() but that's for later).
If for some reason we didn't do it there and we try to execute, we'll hit
the page fault, which will do a minor fault, which will hit ptep_set_access_flags()
to do things like update _PAGE_ACCESSED or _PAGE_DIRTY if needed, we just make
this guys also perform the I/D cache sync for exec faults now. This second path
is the catch all for things that weren't cleaned at set_pte_at() time.
For cpus without per-pag exec support, we always do the sync at set_pte_at(),
thus guaranteeing that when the PTE is visible to other processors, the cache
is clean.
For the 64-bit hash with per-page exec support case, we keep the old mechanism
for now. I'll look into changing it later, once I've reworked a bit how we
use _PAGE_EXEC.
This is also a first step for adding _PAGE_EXEC support for embedded platforms
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
2009-02-10 16:02:37 +00:00
|
|
|
/* huge pages use the old page table lock */
|
|
|
|
if (!huge)
|
|
|
|
assert_pte_locked(mm, addr);
|
|
|
|
|
2009-06-02 21:17:45 +00:00
|
|
|
#ifdef CONFIG_PPC_STD_MMU_64
|
2007-04-30 06:30:56 +00:00
|
|
|
if (old & _PAGE_HASHPTE)
|
|
|
|
hpte_need_flush(mm, addr, ptep, old, huge);
|
2009-06-02 21:17:45 +00:00
|
|
|
#endif
|
|
|
|
|
2007-04-30 06:30:56 +00:00
|
|
|
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)
|
|
|
|
{
|
|
|
|
|
2011-05-07 04:11:31 +00:00
|
|
|
if ((pte_val(*ptep) & _PAGE_RW) == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
pte_update(mm, addr, ptep, _PAGE_RW, 0);
|
2007-04-30 06:30:56 +00:00
|
|
|
}
|
|
|
|
|
powerpc: Add 64 bit version of huge_ptep_set_wrprotect
The implementation of huge_ptep_set_wrprotect() directly calls
ptep_set_wrprotect() to mark a hugepte write protected. However this
call is not appropriate on ppc64 kernels as this is a small page only
implementation. This can lead to the hash not being flushed correctly
when a mapping is being converted to COW, allowing processes to continue
using the original copy.
Currently huge_ptep_set_wrprotect() unconditionally calls
ptep_set_wrprotect(). This is fine on ppc32 kernels as this call is
generic. On 64 bit this is implemented as:
pte_update(mm, addr, ptep, _PAGE_RW, 0);
On ppc64 this last parameter is the page size and is passed directly on
to hpte_need_flush():
hpte_need_flush(mm, addr, ptep, old, huge);
And this directly affects the page size we pass to flush_hash_page():
flush_hash_page(vaddr, rpte, psize, ssize, 0);
As this changes the way the hash is calculated we will flush the wrong
pages, potentially leaving live hashes to the original page.
Move the definition of huge_ptep_set_wrprotect() to the 32/64 bit specific
headers.
Signed-off-by: Andy Whitcroft <apw@shadowen.org>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
2008-06-26 09:55:58 +00:00
|
|
|
static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
|
|
|
|
unsigned long addr, pte_t *ptep)
|
|
|
|
{
|
Correct hash flushing from huge_ptep_set_wrprotect()
As Andy Whitcroft recently pointed out, the current powerpc version of
huge_ptep_set_wrprotect() has a bug. It just calls ptep_set_wrprotect()
which in turn calls pte_update() then hpte_need_flush() with the 'huge'
argument set to 0. This will cause hpte_need_flush() to flush the wrong
hash entries (of any). Andy's fix for this is already in the powerpc
tree as commit 016b33c4958681c24056abed8ec95844a0da80a3.
I have confirmed this is a real bug, not masked by some other
synchronization, with a new testcase for libhugetlbfs. A process write
a (MAP_PRIVATE) hugepage mapping, fork(), then alter the mapping and
have the child incorrectly see the second write.
Therefore, this should be fixed for 2.6.26, and for the stable tree.
Here is a suitable patch for 2.6.26, which I think will also be suitable
for the stable tree (neither of the headers in question has been changed
much recently).
It is cut down slighlty from Andy's original version, in that it does
not include a 32-bit version of huge_ptep_set_wrprotect(). Currently,
hugepages are not supported on any 32-bit powerpc platform. When they
are, a suitable 32-bit version can be added - the only 32-bit hardware
which supports hugepages does not use the conventional hashtable MMU and
so will have different needs anyway.
Signed-off-by: Andy Whitcroft <apw@shadowen.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-07-08 05:58:16 +00:00
|
|
|
if ((pte_val(*ptep) & _PAGE_RW) == 0)
|
|
|
|
return;
|
2011-05-07 04:11:31 +00:00
|
|
|
|
|
|
|
pte_update(mm, addr, ptep, _PAGE_RW, 1);
|
powerpc: Add 64 bit version of huge_ptep_set_wrprotect
The implementation of huge_ptep_set_wrprotect() directly calls
ptep_set_wrprotect() to mark a hugepte write protected. However this
call is not appropriate on ppc64 kernels as this is a small page only
implementation. This can lead to the hash not being flushed correctly
when a mapping is being converted to COW, allowing processes to continue
using the original copy.
Currently huge_ptep_set_wrprotect() unconditionally calls
ptep_set_wrprotect(). This is fine on ppc32 kernels as this call is
generic. On 64 bit this is implemented as:
pte_update(mm, addr, ptep, _PAGE_RW, 0);
On ppc64 this last parameter is the page size and is passed directly on
to hpte_need_flush():
hpte_need_flush(mm, addr, ptep, old, huge);
And this directly affects the page size we pass to flush_hash_page():
flush_hash_page(vaddr, rpte, psize, ssize, 0);
As this changes the way the hash is calculated we will flush the wrong
pages, potentially leaving live hashes to the original page.
Move the definition of huge_ptep_set_wrprotect() to the 32/64 bit specific
headers.
Signed-off-by: Andy Whitcroft <apw@shadowen.org>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
2008-06-26 09:55:58 +00:00
|
|
|
}
|
2007-04-30 06:30:56 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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 the dirty and/or accessed bits atomically in a linux PTE, this
|
|
|
|
* function doesn't need to flush the hash entry
|
|
|
|
*/
|
powerpc/mm: Rework I$/D$ coherency (v3)
This patch reworks the way we do I and D cache coherency on PowerPC.
The "old" way was split in 3 different parts depending on the processor type:
- Hash with per-page exec support (64-bit and >= POWER4 only) does it
at hashing time, by preventing exec on unclean pages and cleaning pages
on exec faults.
- Everything without per-page exec support (32-bit hash, 8xx, and
64-bit < POWER4) does it for all page going to user space in update_mmu_cache().
- Embedded with per-page exec support does it from do_page_fault() on
exec faults, in a way similar to what the hash code does.
That leads to confusion, and bugs. For example, the method using update_mmu_cache()
is racy on SMP where another processor can see the new PTE and hash it in before
we have cleaned the cache, and then blow trying to execute. This is hard to hit but
I think it has bitten us in the past.
Also, it's inefficient for embedded where we always end up having to do at least
one more page fault.
This reworks the whole thing by moving the cache sync into two main call sites,
though we keep different behaviours depending on the HW capability. The call
sites are set_pte_at() which is now made out of line, and ptep_set_access_flags()
which joins the former in pgtable.c
The base idea for Embedded with per-page exec support, is that we now do the
flush at set_pte_at() time when coming from an exec fault, which allows us
to avoid the double fault problem completely (we can even improve the situation
more by implementing TLB preload in update_mmu_cache() but that's for later).
If for some reason we didn't do it there and we try to execute, we'll hit
the page fault, which will do a minor fault, which will hit ptep_set_access_flags()
to do things like update _PAGE_ACCESSED or _PAGE_DIRTY if needed, we just make
this guys also perform the I/D cache sync for exec faults now. This second path
is the catch all for things that weren't cleaned at set_pte_at() time.
For cpus without per-pag exec support, we always do the sync at set_pte_at(),
thus guaranteeing that when the PTE is visible to other processors, the cache
is clean.
For the 64-bit hash with per-page exec support case, we keep the old mechanism
for now. I'll look into changing it later, once I've reworked a bit how we
use _PAGE_EXEC.
This is also a first step for adding _PAGE_EXEC support for embedded platforms
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
2009-02-10 16:02:37 +00:00
|
|
|
static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry)
|
2007-04-30 06:30:56 +00:00
|
|
|
{
|
|
|
|
unsigned long bits = pte_val(entry) &
|
2009-08-18 19:00:34 +00:00
|
|
|
(_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC);
|
2009-03-19 19:34:15 +00:00
|
|
|
|
|
|
|
#ifdef PTE_ATOMIC_UPDATES
|
2007-04-30 06:30:56 +00:00
|
|
|
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");
|
2009-03-19 19:34:15 +00:00
|
|
|
#else
|
|
|
|
unsigned long old = pte_val(*ptep);
|
|
|
|
*ptep = __pte(old | bits);
|
|
|
|
#endif
|
2007-04-30 06:30:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#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)
|
|
|
|
|
2009-10-28 16:27:18 +00:00
|
|
|
void pgtable_cache_add(unsigned shift, void (*ctor)(void *));
|
2007-04-30 06:30:56 +00:00
|
|
|
void pgtable_cache_init(void);
|
|
|
|
#endif /* __ASSEMBLY__ */
|
|
|
|
|
2013-06-20 09:00:15 +00:00
|
|
|
/*
|
|
|
|
* THP pages can't be special. So use the _PAGE_SPECIAL
|
|
|
|
*/
|
|
|
|
#define _PAGE_SPLITTING _PAGE_SPECIAL
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We need to differentiate between explicit huge page and THP huge
|
|
|
|
* page, since THP huge page also need to track real subpage details
|
|
|
|
*/
|
|
|
|
#define _PAGE_THP_HUGE _PAGE_4K_PFN
|
|
|
|
|
|
|
|
/*
|
|
|
|
* set of bits not changed in pmd_modify.
|
|
|
|
*/
|
|
|
|
#define _HPAGE_CHG_MASK (PTE_RPN_MASK | _PAGE_HPTEFLAGS | \
|
|
|
|
_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_SPLITTING | \
|
|
|
|
_PAGE_THP_HUGE)
|
|
|
|
|
|
|
|
#ifndef __ASSEMBLY__
|
|
|
|
/*
|
|
|
|
* The linux hugepage PMD now include the pmd entries followed by the address
|
|
|
|
* to the stashed pgtable_t. The stashed pgtable_t contains the hpte bits.
|
|
|
|
* [ 1 bit secondary | 3 bit hidx | 1 bit valid | 000]. We use one byte per
|
|
|
|
* each HPTE entry. With 16MB hugepage and 64K HPTE we need 256 entries and
|
|
|
|
* with 4K HPTE we need 4096 entries. Both will fit in a 4K pgtable_t.
|
|
|
|
*
|
|
|
|
* The last three bits are intentionally left to zero. This memory location
|
|
|
|
* are also used as normal page PTE pointers. So if we have any pointers
|
|
|
|
* left around while we collapse a hugepage, we need to make sure
|
|
|
|
* _PAGE_PRESENT and _PAGE_FILE bits of that are zero when we look at them
|
|
|
|
*/
|
|
|
|
static inline unsigned int hpte_valid(unsigned char *hpte_slot_array, int index)
|
|
|
|
{
|
|
|
|
return (hpte_slot_array[index] >> 3) & 0x1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline unsigned int hpte_hash_index(unsigned char *hpte_slot_array,
|
|
|
|
int index)
|
|
|
|
{
|
|
|
|
return hpte_slot_array[index] >> 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void mark_hpte_slot_valid(unsigned char *hpte_slot_array,
|
|
|
|
unsigned int index, unsigned int hidx)
|
|
|
|
{
|
|
|
|
hpte_slot_array[index] = hidx << 4 | 0x1 << 3;
|
|
|
|
}
|
|
|
|
|
2013-08-28 08:37:42 +00:00
|
|
|
struct page *realmode_pfn_to_page(unsigned long pfn);
|
|
|
|
|
2013-06-20 09:00:15 +00:00
|
|
|
static inline char *get_hpte_slot_array(pmd_t *pmdp)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* The hpte hindex is stored in the pgtable whose address is in the
|
|
|
|
* second half of the PMD
|
|
|
|
*
|
|
|
|
* Order this load with the test for pmd_trans_huge in the caller
|
|
|
|
*/
|
|
|
|
smp_rmb();
|
|
|
|
return *(char **)(pmdp + PTRS_PER_PMD);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
extern void hpte_do_hugepage_flush(struct mm_struct *mm, unsigned long addr,
|
|
|
|
pmd_t *pmdp);
|
|
|
|
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
|
|
|
extern pmd_t pfn_pmd(unsigned long pfn, pgprot_t pgprot);
|
|
|
|
extern pmd_t mk_pmd(struct page *page, pgprot_t pgprot);
|
|
|
|
extern pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot);
|
|
|
|
extern void set_pmd_at(struct mm_struct *mm, unsigned long addr,
|
|
|
|
pmd_t *pmdp, pmd_t pmd);
|
|
|
|
extern void update_mmu_cache_pmd(struct vm_area_struct *vma, unsigned long addr,
|
|
|
|
pmd_t *pmd);
|
|
|
|
|
|
|
|
static inline int pmd_trans_huge(pmd_t pmd)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* leaf pte for huge page, bottom two bits != 00
|
|
|
|
*/
|
|
|
|
return (pmd_val(pmd) & 0x3) && (pmd_val(pmd) & _PAGE_THP_HUGE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int pmd_large(pmd_t pmd)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* leaf pte for huge page, bottom two bits != 00
|
|
|
|
*/
|
|
|
|
if (pmd_trans_huge(pmd))
|
|
|
|
return pmd_val(pmd) & _PAGE_PRESENT;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int pmd_trans_splitting(pmd_t pmd)
|
|
|
|
{
|
|
|
|
if (pmd_trans_huge(pmd))
|
|
|
|
return pmd_val(pmd) & _PAGE_SPLITTING;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-06-20 09:00:26 +00:00
|
|
|
extern int has_transparent_hugepage(void);
|
2013-06-20 09:00:15 +00:00
|
|
|
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
|
|
|
|
|
|
|
|
static inline pte_t pmd_pte(pmd_t pmd)
|
|
|
|
{
|
|
|
|
return __pte(pmd_val(pmd));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline pmd_t pte_pmd(pte_t pte)
|
|
|
|
{
|
|
|
|
return __pmd(pte_val(pte));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline pte_t *pmdp_ptep(pmd_t *pmd)
|
|
|
|
{
|
|
|
|
return (pte_t *)pmd;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define pmd_pfn(pmd) pte_pfn(pmd_pte(pmd))
|
|
|
|
#define pmd_young(pmd) pte_young(pmd_pte(pmd))
|
|
|
|
#define pmd_mkold(pmd) pte_pmd(pte_mkold(pmd_pte(pmd)))
|
|
|
|
#define pmd_wrprotect(pmd) pte_pmd(pte_wrprotect(pmd_pte(pmd)))
|
|
|
|
#define pmd_mkdirty(pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd)))
|
|
|
|
#define pmd_mkyoung(pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd)))
|
|
|
|
#define pmd_mkwrite(pmd) pte_pmd(pte_mkwrite(pmd_pte(pmd)))
|
|
|
|
|
|
|
|
#define __HAVE_ARCH_PMD_WRITE
|
|
|
|
#define pmd_write(pmd) pte_write(pmd_pte(pmd))
|
|
|
|
|
|
|
|
static inline pmd_t pmd_mkhuge(pmd_t pmd)
|
|
|
|
{
|
|
|
|
/* Do nothing, mk_pmd() does this part. */
|
|
|
|
return pmd;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline pmd_t pmd_mknotpresent(pmd_t pmd)
|
|
|
|
{
|
|
|
|
pmd_val(pmd) &= ~_PAGE_PRESENT;
|
|
|
|
return pmd;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline pmd_t pmd_mksplitting(pmd_t pmd)
|
|
|
|
{
|
|
|
|
pmd_val(pmd) |= _PAGE_SPLITTING;
|
|
|
|
return pmd;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define __HAVE_ARCH_PMD_SAME
|
|
|
|
static inline int pmd_same(pmd_t pmd_a, pmd_t pmd_b)
|
|
|
|
{
|
|
|
|
return (((pmd_val(pmd_a) ^ pmd_val(pmd_b)) & ~_PAGE_HPTEFLAGS) == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define __HAVE_ARCH_PMDP_SET_ACCESS_FLAGS
|
|
|
|
extern int pmdp_set_access_flags(struct vm_area_struct *vma,
|
|
|
|
unsigned long address, pmd_t *pmdp,
|
|
|
|
pmd_t entry, int dirty);
|
|
|
|
|
|
|
|
extern unsigned long pmd_hugepage_update(struct mm_struct *mm,
|
|
|
|
unsigned long addr,
|
|
|
|
pmd_t *pmdp, unsigned long clr);
|
|
|
|
|
|
|
|
static inline int __pmdp_test_and_clear_young(struct mm_struct *mm,
|
|
|
|
unsigned long addr, pmd_t *pmdp)
|
|
|
|
{
|
|
|
|
unsigned long old;
|
|
|
|
|
|
|
|
if ((pmd_val(*pmdp) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0)
|
|
|
|
return 0;
|
|
|
|
old = pmd_hugepage_update(mm, addr, pmdp, _PAGE_ACCESSED);
|
|
|
|
return ((old & _PAGE_ACCESSED) != 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG
|
|
|
|
extern int pmdp_test_and_clear_young(struct vm_area_struct *vma,
|
|
|
|
unsigned long address, pmd_t *pmdp);
|
|
|
|
#define __HAVE_ARCH_PMDP_CLEAR_YOUNG_FLUSH
|
|
|
|
extern int pmdp_clear_flush_young(struct vm_area_struct *vma,
|
|
|
|
unsigned long address, pmd_t *pmdp);
|
|
|
|
|
|
|
|
#define __HAVE_ARCH_PMDP_GET_AND_CLEAR
|
|
|
|
extern pmd_t pmdp_get_and_clear(struct mm_struct *mm,
|
|
|
|
unsigned long addr, pmd_t *pmdp);
|
|
|
|
|
|
|
|
#define __HAVE_ARCH_PMDP_CLEAR_FLUSH
|
|
|
|
extern pmd_t pmdp_clear_flush(struct vm_area_struct *vma, unsigned long address,
|
|
|
|
pmd_t *pmdp);
|
|
|
|
|
|
|
|
#define __HAVE_ARCH_PMDP_SET_WRPROTECT
|
|
|
|
static inline void pmdp_set_wrprotect(struct mm_struct *mm, unsigned long addr,
|
|
|
|
pmd_t *pmdp)
|
|
|
|
{
|
|
|
|
|
|
|
|
if ((pmd_val(*pmdp) & _PAGE_RW) == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
pmd_hugepage_update(mm, addr, pmdp, _PAGE_RW);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define __HAVE_ARCH_PMDP_SPLITTING_FLUSH
|
|
|
|
extern void pmdp_splitting_flush(struct vm_area_struct *vma,
|
|
|
|
unsigned long address, pmd_t *pmdp);
|
|
|
|
|
|
|
|
#define __HAVE_ARCH_PGTABLE_DEPOSIT
|
|
|
|
extern void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,
|
|
|
|
pgtable_t pgtable);
|
|
|
|
#define __HAVE_ARCH_PGTABLE_WITHDRAW
|
|
|
|
extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp);
|
|
|
|
|
|
|
|
#define __HAVE_ARCH_PMDP_INVALIDATE
|
|
|
|
extern void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
|
|
|
|
pmd_t *pmdp);
|
|
|
|
#endif /* __ASSEMBLY__ */
|
2007-04-30 06:30:56 +00:00
|
|
|
#endif /* _ASM_POWERPC_PGTABLE_PPC64_H_ */
|