2007-04-30 08:30:56 +02: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 07:15:36 +02:00
|
|
|
#define PGTABLE_RANGE (ASM_CONST(1) << PGTABLE_EADDR_SIZE)
|
2007-04-30 08:30:56 +02: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 07:15:36 +02:00
|
|
|
|
2007-04-30 08:30:56 +02: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 07:15:36 +02:00
|
|
|
#define VMALLOC_SIZE (PGTABLE_RANGE >> 1)
|
2007-04-30 08:30:56 +02: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 07:15:36 +02: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 08:30:56 +02: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 07:15:36 +02: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 08:30:56 +02: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))
|
[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 07:41:48 +02:00
|
|
|
#define VMEMMAP_REGION_ID (0xfUL)
|
2007-04-30 08:30:56 +02:00
|
|
|
#define USER_REGION_ID (0UL)
|
|
|
|
|
2007-10-16 10:24:17 +02:00
|
|
|
/*
|
[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 07:41:48 +02:00
|
|
|
* Defines the address of the vmemap area, in its own region
|
2007-10-16 10:24:17 +02:00
|
|
|
*/
|
[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 07:41:48 +02:00
|
|
|
#define VMEMMAP_BASE (VMEMMAP_REGION_ID << REGION_SHIFT)
|
|
|
|
#define vmemmap ((struct page *)VMEMMAP_BASE)
|
|
|
|
|
2007-10-16 10:24:17 +02:00
|
|
|
|
2007-04-30 08:30:56 +02: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_BUSY 0x0800 /* software: PTE & hash are busy */
|
|
|
|
|
2008-07-07 16:28:52 +02:00
|
|
|
/* Strong Access Ordering */
|
|
|
|
#define _PAGE_SAO (_PAGE_WRITETHRU | _PAGE_NO_CACHE | _PAGE_COHERENT)
|
|
|
|
|
2007-04-30 08:30:56 +02:00
|
|
|
#define _PAGE_BASE (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_COHERENT)
|
|
|
|
|
|
|
|
#define _PAGE_WRENABLE (_PAGE_RW | _PAGE_DIRTY)
|
|
|
|
|
2008-12-03 14:52:05 +01:00
|
|
|
/* __pgprot defined in arch/powerpc/include/asm/page.h */
|
2007-04-30 08:30:56 +02:00
|
|
|
#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
|
|
|
|
|
2008-10-12 19:54:24 +02:00
|
|
|
#define PAGE_PROT_BITS (_PAGE_GUARDED | _PAGE_COHERENT | \
|
|
|
|
_PAGE_NO_CACHE | _PAGE_WRITETHRU | \
|
|
|
|
_PAGE_4K_PFN | _PAGE_RW | _PAGE_USER | \
|
|
|
|
_PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_EXEC)
|
2007-04-30 08:30:56 +02:00
|
|
|
/* PTEIDX nibble */
|
|
|
|
#define _PTEIDX_SECONDARY 0x8
|
|
|
|
#define _PTEIDX_GROUP_IX 0x7
|
|
|
|
|
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 17:02:37 +01:00
|
|
|
/* To make some generic powerpc code happy */
|
|
|
|
#define _PAGE_HWEXEC 0
|
2007-04-30 08:30:56 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
|
2008-09-03 05:12:05 +02:00
|
|
|
#ifdef CONFIG_PPC_MM_SLICES
|
2007-04-30 08:30:56 +02:00
|
|
|
#define HAVE_ARCH_UNMAPPED_AREA
|
|
|
|
#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
|
2008-09-03 05:12:05 +02:00
|
|
|
#endif /* CONFIG_PPC_MM_SLICES */
|
2007-04-30 08:30:56 +02:00
|
|
|
|
|
|
|
#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;}
|
2008-07-28 05:28:03 +02:00
|
|
|
static inline int pte_special(pte_t pte) { return pte_val(pte) & _PAGE_SPECIAL; }
|
2007-04-30 08:30:56 +02:00
|
|
|
|
|
|
|
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 11:13:00 +02:00
|
|
|
static inline pte_t pte_mkspecial(pte_t pte) {
|
2008-07-28 05:28:03 +02:00
|
|
|
pte_val(pte) |= _PAGE_SPECIAL; return pte; }
|
2008-10-12 19:54:24 +02:00
|
|
|
static inline pgprot_t pte_pgprot(pte_t pte)
|
2008-07-24 06:27:08 +02:00
|
|
|
{
|
2008-10-12 19:54:24 +02:00
|
|
|
return __pgprot(pte_val(pte) & PAGE_PROT_BITS);
|
2008-07-24 06:27:08 +02:00
|
|
|
}
|
2007-04-30 08:30:56 +02: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" );
|
|
|
|
|
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 17:02:37 +01:00
|
|
|
/* huge pages use the old page table lock */
|
|
|
|
if (!huge)
|
|
|
|
assert_pte_locked(mm, addr);
|
|
|
|
|
2007-04-30 08:30:56 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
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 11:55:58 +02:00
|
|
|
static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
|
|
|
|
unsigned long addr, pte_t *ptep)
|
|
|
|
{
|
|
|
|
unsigned long old;
|
|
|
|
|
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 07:58:16 +02:00
|
|
|
if ((pte_val(*ptep) & _PAGE_RW) == 0)
|
|
|
|
return;
|
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 11:55:58 +02:00
|
|
|
old = pte_update(mm, addr, ptep, _PAGE_RW, 1);
|
|
|
|
}
|
2007-04-30 08:30:56 +02: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 17:02:37 +01:00
|
|
|
static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry)
|
2007-04-30 08:30:56 +02:00
|
|
|
{
|
|
|
|
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 __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;
|
|
|
|
}
|
|
|
|
|
2008-07-30 07:23:13 +02:00
|
|
|
pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long address);
|
|
|
|
|
2007-04-30 08:30:56 +02:00
|
|
|
#endif /* __ASSEMBLY__ */
|
|
|
|
|
|
|
|
#endif /* _ASM_POWERPC_PGTABLE_PPC64_H_ */
|